I am fairly new to programming and I'm creating my first application using the model view controller structure.
However; every time I try to output public/home/index/andres, it only displays Array ( [0] => 1 ).
My expected output would've been:
Array (
[0] => home
[1] => index
[2] => andres
)
Can someone please guide me in the right direction?
Below is my .htaccess file as well as my app.php files.
.htaccess:
Options -Multiviews
RewriteEngine On
RewriteBase /public/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php?url=1 [QSA,L]
app.php:
<?php
class App
{
protected $controller = 'home';
protected $method = 'index';
protected $params = [];
public function __construct()
{
print_r($this->parseUrl());
}
public function parseUrl()
{
if(isset($_GET['url']))
{
return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
}
}
}?>
Related
I'm currently testing my project which has MVC integrated in it upon deploying in a free hosting site i've encountered an error 403 this error didn't appear since the development stage. My current knowledge why this error occurs is maybe the type of directives i've used in my htaccess? or something maybe in the core itself any toughts or suggestions to this particular problem :)
domain/
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
</IfModule>
domain/public
<IfModule mod_rewrite.c>
Options -Multiviews
RewriteEngine On
RewriteBase /domain/public
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
</IfModule>
domain/app
Options -Indexes
domain/app/libraries/Core.php
<?php
class Core {
protected $currentController = 'Pages';
protected $currentMethod = 'index';
protected $params = [];
public function __construct(){
//print_r($this->getUrl());
$url = $this->getUrl();
// Look in BLL for first value\
if($url != NULL){
if(file_exists('../app/controllers/' . ucwords($url[0]). '.php')){
// If exists, set as controller
$this->currentController = ucwords($url[0]);
// Unset 0 Index
unset($url[0]);
}
}
// Require the controller
require_once '../app/controllers/'. $this->currentController . '.php';
// Instantiate controller class
$this->currentController = new $this->currentController;
// Check for second part of url
if(isset($url[1])){
// Check to see if method exists in controller
if(method_exists($this->currentController, $url[1])){
$this->currentMethod = $url[1];
// Unset 1 index
unset($url[1]);
}
}
// Get params
$this->params = $url ? array_values($url) : [];
// Call a callback with array of params
call_user_func_array([$this->currentController, $this->currentMethod], $this->params);
}
public function getUrl(){
if(isset($_GET['url'])){
$url = rtrim($_GET['url'], '/');
$url = filter_var($url, FILTER_SANITIZE_URL);
$url = explode('/', $url);
return $url;
}
}
}
I have a problem with PHP 8 routing. I'm creating my MVC "framework" to learn more about OOP. I did routing, controller and view - it works, I'm happy. But I found out that I would test my creation. This is where the problem begins, namely if the path is empty (""), it returns the "Home" view as asked in the routing, but if I enter "/ test" in the URL, for example, I have a return message "404 Not Found - The requested URL was not found on this server. " even though the given route is added to the table. What is wrong?
.htaccess file
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php [QSA,L]
index.php with routes
<?php
/*
* Require Composer
*/
require dirname(__DIR__) . '/vendor/autoload.php';
/*
* Routing
*/
$routes = new Core\Router();
$routes->new('', ['controller' => 'HomeController', 'method' => 'index']);
$routes->new('/test', ['controller' => 'HomeController', 'method' => 'test']);
$routes->redirectToController($_SERVER['QUERY_STRING']);
Router.php file
<?php
namespace Core;
class Router
{
/*
* Routes and parameters array
*/
protected $routes = [];
protected $params = [];
/*
* Add a route to the route board
*/
public function new($route, $params = [])
{
/*
* Converting routes strings to regular expressions
*/
$route = preg_replace('/\//', '\\/', $route);
$route = preg_replace('/\{([a-z]+)\}/', '(?P<\1>[a-z-]+)', $route);
$route = '/^' . $route . '$/i';
$this->routes[$route] = $params;
}
/*
* Get all routes from table
*/
public function getRoutesTable() {
return $this->routes;
}
/*
* Checking if the specified path exists in the route table
* and completing the parameters table
*/
public function match($url)
{
foreach($this->routes as $route => $params) {
if(preg_match($route, $url, $matches)) {
foreach($matches as $key => $match) {
if(is_string($key)) {
$params[$key] = $match;
}
}
$this->params = $params;
return true;
}
}
return false;
}
/*
* Get all params from table
*/
public function getParamsTable() {
return $this->params;
}
/*
* Redirection to the appropriate controller action
*/
public function redirectToController($requestUrl) {
$requestUrl = explode('?', $requestUrl);
$url = $requestUrl[0];
if ($this->match($url)) {
$controller = $this->params['controller'];
$controller = "App\\Controllers\\$controller";
if(class_exists($controller)) {
$controller_obj = new $controller($this->params);
$method = $this->params['method'];
if(method_exists($controller, $method)) {
$controller_obj->$method();
} else {
echo "Method $method() in controller $controller does not exists!";
}
} else {
echo "Controller $controller not found!";
}
} else {
echo "No routes matched!";
}
}
}
View.php file
<?php
namespace Core;
class View {
public static function view($file) {
$filename = "../App/Views/$file.php";
if(file_exists($filename)) {
require_once $filename;
} else {
echo "View $file is not exist!";
}
}
}
HomeController file
<?php
namespace App\Controllers;
use Core\Controller;
use Core\View;
class HomeController extends Controller {
public function index() {
return View::view('Home');
}
public function test() {
return View::view('Test');
}
}
Folder structure
Routes in web browser
I'm using XAMPP with PHP 8.0 and Windows 10.
First of all, choose one of the following two options to proceed.
Option 1:
If the document root is set to be the same as the project root, e.g. path/to/htdocs, in the config file of the web server (probably httpd.conf), similar to this:
DocumentRoot "/path/to/htdocs"
<Directory "/path/to/htdocs">
AllowOverride All
Require all granted
</Directory>
then create the following .htaccess in the project root, remove any .htaccess file from the directory path/to/htdocs/Public and restart the web server:
<IfModule dir_module>
DirectoryIndex /Public/index.php /Public/index.html
</IfModule>
Options FollowSymLinks
RewriteEngine On
RewriteBase /Public/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Option 2:
If the document root is set to be the directory path/to/htdocs/Public in the config file of the web server (probably httpd.conf), similar to this:
DocumentRoot "/path/to/htdocs/Public"
<Directory "/path/to/htdocs/Public">
AllowOverride All
Require all granted
</Directory>
then create the following .htaccess in the directory path/to/htdocs/Public, remove any other .htaccess file from the project root (unless it, maybe, contains some relevant settings, other than DirectoryIndex) and restart the web server::
Options FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
After you decided and proceeded with one of the options above, edit the page index.php as shown bellow:
<?php
//...
/*
* NOTE: A route pattern can not be an empty string.
* If only the host is given as URL address, the slash
* character (e.g. "/") will be set as value of the
* URI path, e.g. of $_SERVER['REQUEST_URI']. Therefore,
* the route pattern should be set to "/" as well.
*/
$routes->new('/', [
'controller' => 'HomeController',
'method' => 'index',
]);
//...
/*
* In order to get the URI path, you must use the server
* parameter "REQUEST_URI" instead of "QUERY_STRING".
*/
$routes->redirectToController(
$_SERVER['REQUEST_URI']
);
Notes:
In regard of changing $_SERVER['QUERY_STRING'] to $_SERVER['REQUEST_URI'], the credits go to #MagnusEriksson, of course.
There can't be an "MVC framework", but a "web framework for MVC-based application(s)". This is, because a framework is just a collection of libraries (not at all correlated with MVC), which, in turn, is used by one or more applications implementing the MVC pattern.
For any further questions, don't hesitate to ask us.
My URL is:
example.com/controller/function/parameter
=> example.com/category/index/category_name
I need:
example.com/category/category_name
I have tried several solutions provided by Stackoverflow questions asked on this, but it´s not working. Either it redirects to home or a 404 page not found.
The options I have tried are:
$route['category'] = "category/index"; //1
$route['category/(:any)'] = "category/index"; //2
$route['category/(:any)'] = "category/index/$1"; //3
Another route is:
$route['default_controller'] = 'home';
The htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|robots\.txt|css)
RewriteRule ^(.*)$ index.php/$1 [L]
In config file I have:
$config['url_suffix'] = '';
I am not sure why you couldn't get it to work.
Here is some test code I created to check this out...
This is using CI 3.1.5.
.htaccess - same as what you have...
Controller - Category.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Category extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function index($category_name = 'None Selected') {
echo "The Category name is " . $category_name;
}
}
routes.php
$route['category/(:any)'] = "category/index/$1"; //3 - this works
$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;
Test URLS
/category/ output: The Category name is None Selected
/category/fluffy-bunnies output: The Category name is fluffy-bunnies
Have a play with that and see if you can find the issue.
I think you have error in your .htaccess file. Please find below code for .htaccess file.
You can use RewriteBase to provide a base for your rewrites.
RewriteEngine On
RewriteBase /campnew/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|robots\.txt|css)
RewriteRule ^(.*)$ index.php/$1 [L]
In Controller your method.
public function index($category_name = null) {
$this->load->model('category_model');
$data = array();
if ($query = $this->category_model->get_records_view($category_name)) {
$data['recordss'] = $query;
}
if ($query2 = $this->category_model->get_records_view2($category_name))
{
$data['recordsc2'] = $query2;
}
$data['main_content'] = 'category';
$this->load->view('includes/template', $data);
}
In Model File
public function get_records_view($category){
$this->db->where('a.linkname', $category);
}
Let me know if it not works.
I've seen/read questions about clean URLs with .htaccess, but for the life of me, I cannot get them to work for my specific needs. I keep getting 404 message.
Example: www.mysite.com/article.php?id=1&title=my-blog-title
I would like for url to be: www.mysite.com/article/1/my-blog-title
Here's what I have so far in my .htaccess:
Options -MultiViews
#DirectorySlash on
RewriteCond %{HTTP_HOST} !^www [NC]
RewriteRule .* http://www.%{HTTP_HOST}%{REQUEST_URI} [L]
# Rewrite for article.php?id=1&title=Title-Goes-Here
RewriteRule ^article/([0-9]+)/([0-9a-zA-Z_-]+) article.php?id=$1&title=$2 [NC,L]
#Rewrite for certain files with .php extension
RewriteRule ^contact$ contact.php
RewriteRule ^blogs$ blogs.php
RewriteRule ^privacy-policy$ privacy-policy.php
RewriteRule ^terms-of-service$ terms-of-service.php
Also, is this how I would link to article? article.php?id=<?php echo $row_rsBlogs['id']; ?>&slug=<?php echo $row_rsBlogs['slug']; ?> or article/<?php echo $row_rsBlogs['id']; ?>/<?php echo $row_rsBlogs['slug']; ?>
I'm using Dreamweaver, but I am comfortable hand coding.
Thanks in advance.
You could use a dispatcher by telling the webserver to redirect all request to e.g. index.php..
In there a dispatch instance analizes the request and invokes certain controllers (e.g. articlesControllers)
class Dispatcher
{
// dispatch request to the appropriate controllers/method
public static function dispatch()
{
$url = explode('/', trim($_SERVER['REQUEST_URI'], '/'), 4);
/*
* If we are using apache module 'mod_rewrite' - shifting that 'request_uri'-array would be a bad idea :3
*/
//array_shift($url);
// get controllers name
$controller = !empty($url[0]) ? $url[0] . 'Controller' : 'indexController';
// get method name of controllers
$method = !empty($url[1]) ? $url[1] : 'index';
// get argument passed in to the method
$parameters = array();
if (!empty($url[2])) {
$arguments = explode('/', $url[2]);
foreach ($arguments as $argument) {
$keyValue = explode('=',$argument);
$parameters[$keyValue[0]] = $keyValue[1];
}
}
// create controllers instance and call the specified method
$cont = new $controller;
if(!method_exists($cont,$method)) {
throw new MethodNotFoundException("requested method \"". $method . "\" not found in controller \"" . $controller . "\"");
}
$cont->$method($parameters);
}
}
in .htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ index.php
I read this post and I want to use similar solution, but with db.
In my site controller after():
$theme = $page->get_theme_name(); //Orange
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
$this->template = View::factory('layout')
I checked with firebug:
fire::log(Kohana::get_module_path('themes')); // D:\tools\xampp\htdocs\kohana\themes/Orange
I am sure that path exists. I have directly in 'Orange' folder 'views' folder with layout.php file.
But I am getting: The requested view layout could not be found
Extended Kohana_Core is just:
public static function get_module_path($module_key) {
return self::$_modules[$module_key];
}
public static function set_module_path($module_key, $path) {
self::$_modules[$module_key] = $path;
}
Could anybody help me with solving that issue?
Maybe it is a .htaccess problem:
# Turn on URL rewriting
RewriteEngine On
# Put your installation directory here:
# If your URL is www.example.com/kohana/, use /kohana/
# If your URL is www.example.com/, use /
RewriteBase /kohana/
# Protect application and system files from being viewed
RewriteCond $1 ^(application|system|modules)
# Rewrite to index.php/access_denied/URL
RewriteRule ^(.*)$ / [PT,L]
RewriteRule ^(media) - [PT,L]
RewriteRule ^(themes) - [PT,L]
# Allow these directories and files to be displayed directly:
# - index.php (DO NOT FORGET THIS!)
# - robots.txt
# - favicon.ico
# - Any file inside of the images/, js/, or css/ directories
RewriteCond $1 ^(index\.php|robots\.txt|favicon\.ico|static)
# No rewriting
RewriteRule ^(.*)$ - [PT,L]
# Rewrite all other URLs to index.php/URL
RewriteRule ^(.*)$ index.php/$1 [PT,L]
Could somebody help?
What I am doing wrong?
Regards
[EDIT]
My controller code:
class Controller_Site extends Controller_Fly {
public static $meta_names = array('keywords', 'descriptions', 'author');
public function action_main() {
$this->m('page')->get_main_page();
}
public function action_page($page_title) {
$this->m('page')->get_by_link($page_title);
}
public function after() {
$page = $this->m('page');
$metas = '';
foreach(self::$meta_names as $meta) {
if (! empty($page->$meta)) {
$metas .= html::meta($page->$meta, $meta).PHP_EOL;
}
}
$theme = $page->get_theme_name();
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
$menus = $page->get_menus();
$this->template = View::factory('layout')
->set('theme', $theme)
->set('metas', $metas)
->set('menus', $menus['content'])
->set('sections', $page->get_sections())
->set_global('page', $page);
if ($page->header_on) {
$settings = $this->m('setting');
$this->template->header = View::factory('/header')
->set('title', $settings->title)
->set('subtitle', $settings->subtitle)
->set('menus', $menus['header']);
}
if ($page->sidebar_on) {
$this->template->sidebar = View::factory('sidebar', array('menus' => $menus['sidebar']));
}
if ($page->footer_on) {
$this->template->footer = View::factory('footer');
}
parent::after();
}
}
and parent controller:
abstract class Controller_Fly extends Controller_Template {
protected function m($model_name, $id = NULL) {
if (! isset($this->$model_name)) {
$this->$model_name = ORM::factory($model_name, $id);
}
return $this->$model_name;
}
protected function mf($model_name, $id = NULL) {
return ORM::factory($model_name, $id);
}
}
[Edit 2]
Previous link to post was dead, link was:
http://forum.kohanaframework.org/comments.php?DiscussionID=5744&page=1#Item_0
My guess is that your controller has a __construct() method and you aren't calling parent::__construct
Actually, I think for kohana V3 __construct needs to also be passed the $request object as follows:
public function __construct(Request $request)
{
parent::__construct($request);
}
I realized that I need to init all modules once again:
$theme = $page->get_theme_name();
Kohana::set_module_path('themes', Kohana::get_module_path('themes').'/'.$theme);
Kohana::modules(Kohana::get_modules());
Now I don't have an error. Instead I am getting white screen of death:
$this->template is null
:(
[EDIT]
Now I know, I had:
$this->template = View::factory('layout')
->set('theme', $theme)
->set('metas', $metas)
->set('menus', $menus['content'])
->set('sections', $page->get_sections())
->set_gobal('page', $page);
Ofcourse I forgot that set_global doesn't return $this :D
Anyway everything working now :)
I have one more question about efficiency. I am calling Kohana::modules() second time in request flow. Is this a big deal according to efficiency?
Regards