This is my main index file I want that when I write in the browser about it loads the about page but it fails.
<?php
$database = require 'core/bootstrap.php';
require Router::load('routes.php')
->direct(Request::uri());
?>
This is my routes.php file
<?php
$router->define([
'' => 'controllers/index.php',
'about' => 'controllers/about.php',
'about-culture' => 'controllers/about-culture.php',
'contact' => 'controllers/contact.php'
]);
?>
This is my Router file
<?php
class Router
{
protected $routes = [];
public static function load($file)
{
$router = new static;
require $file;
return $router;
}
public function define($routes)
{
$this->routes = $routes;
}
public function direct($uri)
{
if(array_key_exists($uri , $this->routes))
{
return $this->routes[$uri];
}
throw new Exception('No Routes defined for this URL');
}
}
?>
I don`t know what is the error here, I tried a lot and also watch the tutorial and do exactly as he do but I fail to show the output.
require Router::load('routes.php')
->direct(Request::uri());
when I write only the start localhost:8080/start/ (this is the folder where all my files are present , it gives me this error
Fatal error: Uncaught Exception: No Routes defined for this URL in C:\xampp\htdocs\start\core\Router.php:25 Stack trace: #0 C:\xampp\htdocs\start\index.php(8): Router->direct('start') #1 {main} thrown in C:\xampp\htdocs\start\core\Router.php on line 25
and when I load page like about it says object not found.
Request class
<?php
class Request
{
public static function uri()
{
return trim($_SERVER['REQUEST_URI'], '/');
}
}
?>
Basically REQUEST_URI contains the whole url except hostname and protocol since start is your folder name and root directory of your application your have to get request uri after start
for eg
http://localhost/start/about/
REQUEST_URI = /start/about/
after trimming = start/about
which will not match any router.
so you have to pass your base directory to your function somehow one way is to modify your uri function
class Request
{
public static function uri($base = "")
{
$url = str_replace($base,"",$_SERVER['REQUEST_URI']);
return trim( $url , '/');
}
}
and can be called as Request::uri("start")
Related
Confession:
I read many similar questions on this platform, but nothing seems closely aligned to my situation. Most of the questions seem to originate from binding params in prepared statements or execute statement.
In my case, the website runs smooth on a local server(Apache2). However, it throws the error below when published on live server.
Fatal error: Uncaught Error: Call to a member function signin() on boolean in /storage/ssd5/815/17670815/app/controllers/signin.php:16 Stack trace: #0 /storage/ssd5/815/17670815/app/core/app.php(33): Signin->index() #1 /storage/ssd5/815/17670815/public_html/index.php(4): App->__construct() #2 {main} thrown in /storage/ssd5/815/17670815/app/controllers/signin.php on line 16
Context
I'm using MVC (OOP) in PHP and here the relevant parts mentioned in the error. I hope this is not too much.
In the main index page, the line referred in the error is a core class(App) instantiation
<?php
session_start();
require_once '../app/initializer.php';
$app = new App(); //this is the line 4 mentioned in the error
In Signin controller class the line referred in the error is indicated below
<?php
class Signin extends Controller{
function index(){
//you can do this if passing data to view
$data["Page_title"] = "Signin";
if($_SERVER['REQUEST_METHOD'] == "POST"){
// this is a debuggin code
//echo "I am signin controller <br />";
// show($_POST);
$user = $this->loadModel("User");
$user->signin($_POST); //this the line referred in the error
}
$this->view("zac/signin",$data);
}
}
In class APP the line is a callback - check below
<?php
class App {
private $controller = "home";
private $method = "index";
private $params = [];
public function __construct()
{
$url = $this->splitURL();
if(file_exists("../app/controllers/".strtolower($url[0]).".php")){
$this->controller = strtolower($url[0]);
//unset the array position
unset($url[0]);
}
require "../app/controllers/".$this->controller.".php";
// echo file_get_contents('http://smart-ecom.000webhostapp.com/app/controllers/'.$this->controller.".php");
//Create instance of whatever controller class is passed(if it exists, otherwise the home controller)
$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 = array_values($url);
call_user_func_array([$this->controller, $this->method],$this->params); //this is line 33
}
/**
* splitURL gets url from browser and processes against the conroller classes and their methods
* #return array
*/
private function splitURL(){
//check if the the GET is set otherwise set the url to defualt class home
$url = isset($_GET['url']) ? $_GET['url'] :"home";
// return explode("/",filter_var(trim($_GET['url'],"/"), FILTER_SANITIZE_URL));
return explode("/",filter_var(trim($url,"/"), FILTER_SANITIZE_URL));
}
}
?>
The Database class's read function is as follows. This method isn't directly referred in the error message
public function read($query, $data = []){
$stmt = self::$conn->prepare($query);
$result = $stmt->execute($data);
if($result){
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
if(is_array($data) && count($data) > 0){
return $data;
}
}
return false;
}
As I mentioned earlier, this error fires on a live server but the website runs smooth in dev environment with PHP 7.4, Apache2, MySQL 8 Windows 10.
Your help is match appreciated in advance.
I learned this the hard way and I hope this can help someone with similar issues. The cause of the error because of how windows and Linux deals with case sensitivity in file names. In Windows, file names aren't case sensitive while in Linux - they are. So, that was the reason why the website was running smooth in the local dev environment(Windows machine) but throwing an error on a live server(which is Linux). To see the difference, refer to my earlier comment in this thread.
protected function loadModel($model){
if(file_exists("../app/models/". strtolower($model) . ".class.php")){
include "../app/models/".strtolower($model).".class.php";
return $model = new $model();
}else{
return false;
}
}
}
In the "include" line, you can see that I added the strtolower function to include the proper model and that solved the issue.
While upgrading to PHP7, I encountered these problem.
The issue is am trying to create codes that I can reuse like a mini-framework and the RUN function where the problem is used to load the relevant template and supplying the variables. It complains about
undefined index
of these 2 variables
$controller = $routes[$this->route][$this->method]['controller'];
$action = $routes[$this->route][$this->method]['action'];
and it also complained about this line
$page = $controller->$action();
which displayed
Fatal error: Uncaught Error: Method name must be a string in...
public function run() {
$routes = $this->routes->getRoutes();
$authentication = $this->routes->getAuthentication();
if (isset($routes[$this->route]['login']) && !$authentication->isLoggedIn()) {
header('location: /login/error');
}
else if (isset($routes[$this->route]['permissions']) && !$this->routes->checkPermission($routes[$this->route]['permissions'])) {
header('location: /login/permissionserror');
}
else {
$controller = $routes[$this->route][$this->method]['controller'];
$action = $routes[$this->route][$this->method]['action'];
$page = $controller->$action();
$title = $page['title'];
if (isset($page['variables'])) {
$output = $this->loadTemplate($page['template'], $page['variables']);
}
else {
$output = $this->loadTemplate($page['template']);
}
echo $this->loadTemplate('layout.html.php', ['loggedIn' => $authentication->isLoggedIn(),
'output' => $output,
'title' => $title
]);
}
This is the index.php
try {
include __DIR__ . '/../includes/autoload.php';
$route = ltrim(strtok($_SERVER['REQUEST_URI'], '?'), '/');
$entryPoint = new \Ninja\EntryPoint($route, $_SERVER['REQUEST_METHOD'], new \Ijdb\IjdbRoutes());
$entryPoint->run();
}
catch (PDOException $e) {
$title = 'An error has occurred';
$output = 'Database error: ' . $e->getMessage() . ' in ' .
$e->getFile() . ':' . $e->getLine();
include __DIR__ . '/../templates/layout.html.php';
}
The code is much, so, I can't display the whole code here since am using MVC pattern, but if there is anything you still want to know, I will gladly post it here
This code is runnable in php 7.2.7 (MAMP and LAMP), your way of dynamic function calling is invalid and your two variables are empty. This is not exact as yours but you can take logic form this demo.
Ok i am just providing a very simple example of reflection with mapping url to class along with functions. I make folder structure like below-
Here .htaccess is used to redirect all the url to index.php (if no file exists).
index.php include all code that could initialize code(for now only three files were there - uri.php, urlMapping.php and actions.php)
URI.php - have function that provide values like basepath, baseurl, uri
urlMappig.php - that allows you to provide which url hit which class along with method
actions.php will call dynamic class and function (reflection)
now look into code of index.php
<?php
include_once('URI.php');
include_once('urlMapping.php');
include_once('actions.php');
?>
aNow code insise uri.php file -
<?php
// all function should be accessible to all file loaded now
// return full url
function full_url (){
return (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
}
// returns current directory
function directory() {
$parts = explode("/", __DIR__);
return $parts[count($parts)-1];
}
// return base url
function base_url(){
$dir = directory();
return substr(full_url(), 0, strpos(full_url(), $dir)+strlen($dir));
}
// return uri
function uri() {
return substr(full_url(), strlen(base_url())+1);
}
?>
Now code in urlMapping.php
Note - file name and name of the class must be same as you map url in
this file so that you can make call to dynamic classes and function on actions.php. If don't this will not work
<?php
// this $urlMap will be accessed in actions.php
$urlMap = [
// here we use only uri so .. https://example.com/login hit LoginController class along with login function, this is just only the mapping
'login' => ['class'=>'LoginController',
'function'=>'login'],
];
?>
Now actions.php code
<?php
// if call is not like example.com/ means no uri is there
if(uri()!='')
{
// if your uri exists in route collection or urlmapping collection then make call to your dynamic class and methods
if(array_key_exists(uri(), $urlMap))
{
// include the class file dynamically from controllers folder
include_once('controllers/'.$urlMap[uri()]['class'].'.php');
// making references for dynamic class
$controlerObject = new $urlMap[uri()]['class']();
// call function dynaically from the referece
$controlerObject->{$urlMap[uri()]['function']}();
}
else
{
// you can make 404 page not
echo 'No routing found';
}
}
// call for home page
else
{
include_once('index.html.php');
}
?>
Now controllres/LoginController.php class,
Note - As mentioned above file name and name of the class as in urlMapping.php
<?php
class LoginController{
public function login()
{
// .... something your code goes here
echo 'hello from the login function of login controller';
}
//...... other function you can define
}
?>
Before calling $page = $controller->$action(); check if controller and action are exists:
if (isset($routes[$this->route][$this->method]['controller'])
&& isset($routes[$this->route][$this->method]['action'])) {
$controller = $routes[$this->route][$this->method]['controller'];
$action = $routes[$this->route][$this->method]['action'];
$page = $controller->$action();
// ...
} else {
// return 404 Page not found
}
I'm trying to catch the URL from my localhost, here it is
http://localhost/mvc/index.php?url=Index/category and things are going well but when I'm trying to use the URL /category it is showing error. Here is the error
Notice: Array to string conversion in C:\xampp\htdocs\mvc\index.php on line 21
Notice: Undefined property: Index::$Array in C:\xampp\htdocs\mvc\index.php on line 21
Fatal error: Uncaught Error: Function name must be a string in C:\xampp\htdocs\mvc\index.php:30 Stack trace: #0 {main} thrown in C:\xampp\htdocs\mvc\index.php on line 21
<?php
include_once "system/libs/main.php";
include_once "system/libs/Dcontroller.php";
include_once "system/libs/Load.php";
?>
<?php
$url = isset($_GET['url']) ? $_GET['url'] : NULL;
if ($url != NULL) {
$url = rtrim($url,'/');
$url = explode("/", filter_var($url,FILTER_SANITIZE_URL));
} else {
unset($url);
}
if (isset($url[0])){
include 'app/controllers/'.$url[0].'.php';
$ctlr = new $url[0]();
if (isset($url[2])) {
$ctlr->$url[1]($url[2]);
} else {
if (isset($url[1])) {
$ctlr->$url[1](); //Here is the line where I'm getting the
error
} else {
}
}
}else{
include 'app/controllers/Index.php';
$ctlr = new Index();
$ctlr->home();
}
?>
But when I'm using
category() instead of $url[1]
it's working fine. Here is the Index class.
<?php
class Index extends Dcontroller
{
public function __construct()
{
parent::__construct();
}
public function home()
{
$this->load->view("home");
}
public function category()
{
$data = array();
$catModel = $this->load->model("CatModel");
$data['cat'] = $catModel->catList();
$this->load->view("category", $data);
}
}
two things straight away: "/" is not legal in a url param as part of a get string. you need to encapsulate it with URL encodeing
EG:
http://localhost/mvc/index.php?url=Index%2Fcategory
it's also the fact that "$ctlr->$url[1]" simply doesn't have a function called it.. eg: whatever "$ctlr->$url[1]" resolves to ??category()?? doesn't exist, you need to MAKE it.
add this to your code
function category() {
Index tmp = new Index();
tmp->category();
}
EDIT : I've just noticed, it's even more idiotic than I thought.. your string says Index/category doesn't it?.. make the class method static.. (this code is dreadful by the way it displays almost no sound knowledge of design whatsoever) there is no Index/category because you can't call category inside a class except if it's a static method.
Learn to code.
Just started development in the Phalcon PHP framework and am also pretty new to PHP in general. My question is on how to create a request with a route, which I believe I have done, and pass the parameters of the route to the controller action that is linked to the said route. Below I have included the three files that I have been working on and summarize what each one is supposed to do. I also have the end result and where my problem lies directly.
The first file is the index.php file that takes in all route requests for my site.
<?php
//Include all routes on site
foreach (glob("../app/routes/*.php") as $filename)
{
include $filename;
}
foreach (glob("../app/controllers/*.php") as $filename)
{
include $filename;
}
//Create routes and initialize routes
$router = new \Phalcon\Mvc\Router();
$router->mount(new PublicRoutes());
$router->mount(new ApiRoutes());
$router->mount(new AdminRoutes());
$router->handle();
$controller = $router->getControllerName();
$action = $router->getActionName();
$params = $router->getParams();
$di = new \Phalcon\DI\FactoryDefault();
$d = new Phalcon\Mvc\Dispatcher();
$d->setDI($di);
$d->setControllerName($router->getControllerName());
$d->setActionName($router->getActionName());
$d->setParams($router->getParams());
$controller = $d->dispatch();
The second file is the actual routes mounted in for my API call which I am testing everything out with.
<?php
class ApiRoutes extends Phalcon\Mvc\Router\Group
{
public function initialize()
{
//Basic api route for pixelpusher
$this->add(
"/addhawk/api/:action/:model/:params",
array(
"controller" => "api",
"action" => 1,
"model" => 2,
"params" => 3,
)
);
}
}
The third, and final file is the controller class for the API with the only action I am testing right now.
<?php
class ApiController extends \Phalcon\Mvc\Controller
{
public function handlerAction()
{
//Pull in parameters
echo "<h1>API Handler Entered</h1>";
$model = $this->dispatcher->getParam("model");
echo $model;
//Choose correct api based off of api param
if( $model == "grid" ) {
echo 'grid';
}
else if ( $model == "admin" ) {
echo 'admin';
}
else {
//No valid api must have been found for request
}
//Return result from api call
return true;
}
}
So, the url is "localhost/addhawk/api/handler/grate/view" which results in the following output in html courtesy of line 9 in the ApiController.
There is no print out of the $model variable as it should do. There is also no error so I have no idea why it's not printing. According to the documentation and every resource I have read online, all parameters should be available directly from each controller action thanks to the dispatcher and $di class or something similar. So my question is why can I not access the parameters if everything seems to be saying I should be able to?
I have a class which is meant to "load" an another class, however I haven't been able to get it to work.
Error Message
Fatal error: Call to undefined method stdClass::echoString() in C:\Program Files (x86)\EasyPHP-DevServer-14.1VC11\data\localweb\classes\example.php on line 5
Code
My code is broken up into three main sections:
api.php - the class to load the other classes.
API/exampleExternalAPI.php - (multiple files) the classes that api.php loads
example.php - the file that uses the main class (api.php)
If it helps these files can be downloaded from my dropbox
api.php
<?php
/* Config */
define('pathToAPIs','API/');
/* Autoload Function */
spl_autoload_register(function($className){
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=pathToAPIs.(empty($namespace)?"":$namespace."/")."{$className}.php";
include_once($class);
});
class api {
private $listOfAPIs;
public $APIs;
public function __construct($setAPI = null){
$this->updateListOfAPIs();
if (isset($setAPI)){
return $this->setAPI($setAPI);
}
}
public function setAPIs($setAPIs){
$this->APIs = null; // clears a previous call to this method
if (!is_array($setAPIs)){ // if not an array
$setAPIs = array($setAPIs); // make array
}
foreach ($setAPIs as $setAPIType){
if(in_array($setAPIType,$this->listOfAPIs)){
$array[$setAPIType] = new $setAPIType;
}
}
$this->APIs = json_decode(json_encode($array), FALSE); // convert array of required api objects to an object
return $this->APIs;
}
public function getListOfAPIs($update = false){
if ($update){
$this->updateListOfAPIs();
}
return $this->listOfAPIs;
}
private function updateListOfAPIs(){
$this->listOfAPIs = null; // clears a previous call to this method
$it = new FilesystemIterator(pathToAPIs);
foreach ($it as $fileinfo){
$filename = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME); // removes extension
$this->listOfAPIs[]= $filename;
}
}
public function __call($method,$args){
}
}
API/exampleExternalAPI.php
<?php
class exampleExternalAPI {
public function echoString($string){
echo $string;
}
}
example.php
<?php
require_once 'api.php';
$api = new api();
$api->setAPIs('exampleExternalAPI');
$api->APIs->exampleExternalAPI->echoString('string');
Background Info
(may give some insight to my madness)
I'm working on a project where I need to connect to lots of external APIs.
So I decided to creating a class to look after all my communications with external APIs ( not sure if best way - new to Object Oriented Programming).
I'm not entirely sure what problem you're trying to solve, but if your APIs is a simple stdClass instance it should work as expected:
public function setAPIs($setAPIs)
{
$this->APIs = new stdClass; // clears a previous call to this method
if (!is_array($setAPIs)) { // if not an array
$setAPIs = array($setAPIs); // make array
}
foreach ($setAPIs as $setAPIType) {
if (in_array($setAPIType, $this->listOfAPIs)) {
$this->APIs->{$setAPIType} = new $setAPIType;
}
}
return $this->APIs;
}