require_once has failed to include the template file. Why? - php

The following code is showing the following error:
Warning: require_once(/home/..../public_html/edu) [function.require-once]: failed to open stream: Success in /home/..../public_html/edu/index.php on line 25
Fatal error: require_once() [function.require]: Failed opening required '' (include_path='.:/usr/lib/php:/usr/local/lib/php') in /home/..../public_html/edu/index.php on line 25
How can I solve this problem?
<?php
class Model
{
public $tstring;
public function __construct(){
$this->tstring = "The string has been loaded through the template.";
$this->template = "tpl/template.php";
}
}
class View
{
private $model;
public function __construct($model) {
$this->controller = $controller;
$this->model = $model;
}
public function output(){
$data = "<p>" . $this->model->tstring ."</p>";
require_once($this->model->template); //line 25 Attention!!!!!!!!
}
}
class Controller
{
private $model;
public function __construct($model){
$this->model = $model;
}
public function clicked() {
$this->model->string = "Updated Data, thanks to MVC and PHP!";
}
}
$model = new Model();
$controller = new Controller($model);
$view = new View($controller, $model);
echo $view->output();

I find things are greatly simplified when you use relative or absolute/relative paths - so you get to the file you're requiring via the file that requires it, instead of the root directory.
For instance, let's say you have a setup like this:
--/
|
| --var
|
|--www
|
|--html
|
|--index.php
|
|--includes
|
|--util.php
A client runs the index.php file. Let's say that index.php needs to include util.php are three ways to do this (the following lines would exist in index.php)
Absolute:
require_once('/var/www/html/includes/util.php');
Relative:
require_once('./includes/util.php');
Absolute/Relative:
require_once(dirname(__FILE__).'/includes/util.php');
As you can see, the absolute method addresses the util.php file starting from the / directory. The relative method addresses util.php by starting from index.php, and supplying the path that gets from index.php to util.php. The absolute/relative method actually RESOLVES to the absolute method because the string dirname(__FILE__).'/includes/util.php' will actually resolve to "/var/www/html/includes/util.php", but the functionality still appears as relative because you only need to think about the path that gets from index.php to util.php.
I tend to prefer the absolute/relative approach.
Instead of $this->template = "tpl/template.php" you may want to try
$this->template = dirname(__FILE__).'/tpl/template.php';
Even if you still have a problem at this point, you can echo your $this->template variable in order to see exactly what file you are addressing.
Confused about the dirname(__FILE__) part? Here are some links.
dirname
http://ca1.php.net/dirname
__FILE__
http://us2.php.net/manual/en/language.constants.predefined.php
Hope this helps and good luck!

Related

require_once : failed to open stream

I read on SO and experiment with some answers but my code does not work:
I have two classes: C:\Apache24\htdocs\phpdb\classes\dbconnection\mysqlconnection\MySqlConnection.php
and C:\Apache24\htdocs\phpdb\classes\utilities\mysqlutilities\CreateTableDemo.php.
In CreateTableDemo I have the following code:
namespace utilities\mysqlutilities;
use dbconnection\mysqlconnection\MySqlConnection as MSC;
spl_autoload_register(function($class){
$class = 'classes\\'.$class.'.php';
require_once "$class";
});
I get the following warning:
`Warning: require_once(classes\dbconnection\mysqlconnection\MySqlConnection.php): failed to open stream: No such file or directory in C:\Apache24\htdocs\phpdb\classes\utilities\mysqlutilities\CreateTableDemo.php on line 10`.
I understand the warning, the script does not find the namespaced class in the same folder, so I changed the spl_autoload_register to look for a relative path: __DIR__."\\..\\..\\classes\\.$class.'.php'. I get the
warning: `Warning: require_once(C:\Apache24\htdocs\phpdb\classes\utilities\mysqlutilities\..\..\classes\dbconnection\mysqlconnection\MySqlConnection.php): failed to open stream: No such file or directory in C:\Apache24\htdocs\phpdb\classes\utilities\mysqlutilities\CreateTableDemo.php on line 10`.
I cannot find a way to direct the script to the namespaced class.
Thanks in advance for any help.
Create a autoloader-class in a separate file:
class Autoloader {
static public function loader($path) {
$filename = __DIR__.'/classes/'.str_replace("\\", '/', $path).".php";
if (file_exists($filename)) {
include($filename);
$aClass = explode('\\', $path);
$className = array_pop($aClass);
if (class_exists($className)) {
return TRUE;
}
}
return FALSE;
}
}
spl_autoload_register('Autoloader::loader');
And include it in you index file (or whatever).
It will load all your namespaced classes located in folder "classes".
require_once '/PATH_TO/autoload.php';
BTW: the trick is to replace the backslashes to regular slashes.
Works fine for me.
EDIT: Place the autoloader.php at same level like your "classes" folder is. :-)
It's failing because the path to the class is wrong relative to where you are requiring from. Try:
namespace utilities\mysqlutilities;
use dbconnection\mysqlconnection\MySqlConnection as MSC;
spl_autoload_register(function($class){
$exp = explode('classes', __DIR__);
$base = reset($exp);
$class = $base."classes".DIRECTORY_SEPARATOR.$class.".php";
require_once $class;
});

Php routes does not change the effect in the browser bar

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")

In PHP, when autoloading files, where PHP will look for these files?

I have an MVC-based application with a basic URL-rewriting rule, which makes the URL look like this: website/controller/action/id. The id is optional.
If a user enters an invalid action, he should get an error which is handled in the class ErrorController.
All of my classes files are required in an autoloader file, so I should not require them every time I want to create an object. I use spl_autoload_register() for autoloading.
The problem occurs when I try to entering a URL with an invalid action. For example, for the URL website/main/inde (instead of index) - an instance of ErrorController should be created.
Instead, I get this two PHP errors:
Warning: require(!core/errorcontroller.php): failed to open stream: No
such file or directory in
D:\Programs\Wamp\www\fanfics\v0.0.2!core\autoloader.php on line 5
And
Fatal error: require(): Failed opening required
'!core/errorcontroller.php' (include_path='.;C:\php\pear') in
D:\Programs\Wamp\www\fanfics\v0.0.2!core\autoloader.php on line 5
Here is a visual of my files (the exclamation mark before the core folder is for keeping it on the top):
index.php:
<?php
require "!core/autoloader.php";
$loader = new Loader();
!core/autoloader.php
<?php
function autoload_core_classes($class)
{
require "!core/" . strtolower($class) . ".php";
}
function autoload_controllers($class)
{
require "controllers/" . str_replace("controller", "", strtolower($class)) . ".php";
}
function autoload_models($class)
{
require "models/" . str_replace("model", "", strtolower($class)) . ".php";
}
spl_autoload_register("autoload_core_classes");
spl_autoload_register("autoload_controllers");
spl_autoload_register("autoload_models");
!core/basecontroller.php
<?php
abstract class BaseController
{
protected $model;
protected $view;
private $action;
public function __construct($action)
{
$this->action = $action;
$this->view = new View(get_class($this), $action);
}
public function executeAction()
{
if (method_exists($this->model, $this->action))
{
$this->view->output($this->model->{$this->action}());
}
else
{
// Here I create an ErrorController object when the action is invalid
$error = new ErrorController("badmodel");
$error->executeAction();
}
}
}
If I try to require controllers/error.php specifically - it works just fine:
.
.
.
else
{
require "controllers/error.php"; // With this line it works just fine
$error = new ErrorController("badmodel");
$error->executeAction();
}
After an online really long search, I understand that there is maybe a problem with the include_path, but I do not quite understand it. How can I solve this problem?
It's a good idea for each autoloader function to check if the file exists before blindly trying to include/require it. Autoloaders are not expected to throw any errors and should fail silently so they can allow the next autoloader in the queue to attempt to autoload the necessary files.
<?php
function autoload_core_classes($class)
{
if (is_readable("!core/" . strtolower($class) . ".php"))
include "!core/" . strtolower($class) . ".php";
}
function autoload_controllers($class)
{
if (is_readable("controllers/" . str_replace("controller", "", strtolower($class)) . ".php"))
include "controllers/" . str_replace("controller", "", strtolower($class)) . ".php";
}
function autoload_models($class)
{
if (is_readable( "models/" . str_replace("model", "", strtolower($class)))
include "models/" . str_replace("model", "", strtolower($class)) . ".php";
}
spl_autoload_register("autoload_core_classes");
spl_autoload_register("autoload_controllers");
spl_autoload_register("autoload_models");
PHP searches for inclusions in paths defined into the property include_path. For command line you can check its value with:
php -i | grep include_path
For web check it with:
phpinfo()
In any case you can modify the value within php.ini.
I used to chdir() in the root of the project in my single entry point and then include files with relative path from root. This is working because include_path usually contains the current directory "."

Autoloading problems using spl_autoload_register

First off, i like to tell you my directory structure
- /var/www
|- /social_network/
|- index.php
|- /application/
|-/controllers/
|-user.php
|- /models/
|- framework.php
|-/tmp/
In my index.php i include application/framework.php
here is my framework.php code
<?php
spl_autoload_register();
class Framework{
public function load($page, $data){
if(is_array($data)){
extract($data);
}
include "views/".$page;
}
}
$object = "controller\\$controller";
$object = new $object;
if(method_exists($object,"$method")){
$object->$method();
} else {
show_404();
}
?>
Now with the above code, auto loading my class works fine.
In case you are wondering $method and $controller comes from index.php depending on the URI.
Now a friend of mine told me this is wrong way to do it so i changed my code to
<?php
function autoload_controller($controller){
include "$controller.php";
}
spl_autoload_register('autoload_controller');
class Framework{
public function load($page, $data){
if(is_array($data)){
extract($data);
}
include "views/".$page;
}
}
$object = "controller\\$controller";
$object = new $object;
if(method_exists($object,"$method")){
$object->$method();
} else {
show_404();
}
?>
Now i get this error below
Warning: include(controller\User.php): failed to open stream: No such file or directory in /var/www/social_network/application/framework.php on line 3 Warning: include(): Failed opening 'controller\User.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/social_network/application/framework.php on line 3 Fatal error: Class 'controller\User' not found in /var/www/social_network/application/framework.php on line 16
How can i fix this, i have been at this for hours and also if it is possible please show me how i can call a model from models directory from inside a controller class using autoload
Thanks
set_include_path(get_include_path().PATH_SEPARATOR.'/var/www/social_network/application/');
or some constant instead of hard coded string

PHP global, nested/inherited autoload

PHP 5.3.3-pl1-gentoo (cli) (built: Aug
17 2010 18:37:41)
Hi all, I use a simple autoloader in my project's main file (index.php):
require_once("./config.php");
require_once("./app.php");
require_once("./../shared/SqlTool.php");
function __autoload($className) {
$fn = 'file-not-exists-for-{$className}';
if (file_exists("./specific/php/{$className}.php")) { $fn = "./specific/php/{$className}.php"; } else
{ $fn = "./../shared/{$className}.php";}
require_once($fn);
}
$sql = new SqlHD(); // class SqlHD, in ./specific/php/SqlHD.php extends SqlTool
$web = new HTMLForm($sql); // class HTMLForm in HTMLForm.php
$app = new App($sql, $web); // class App in App.php
$app->Main();
The problem: without that require_once("./../shared/SqlTool.php");, script can't execute SqlHD.php, because it can't find SqlTool.php by itself, and for some reason it doesn't uses autoload routine defined in main file.
I tried this:
spl_autoload_register(__NAMESPACE__ .'\Test::load');
class Test {
static public function load($className){
$fn = 'file-not-exists-for-{$className}';
if (file_exists("./specific/php/{$className}.php")) { $fn = "./specific/php/{$className}.php"; } else
{ $fn = "./../shared/{$className}.php}";}
echo realpath($fn);//"$curRealDir Filename $fn\n";
echo "\n";
require_once($fn);
}
}
Well,
PHP Warning:
require_once(./../shared/SqlTool.php}):
failed to open stream: No such file or
directory in
/home/beep/work/php/hauthd/index.php
on line 20 PHP Fatal error:
require_once(): Failed opening
required './../shared/SqlTool.php}'
(include_path='.:/usr/share/php5:/usr/share/php')
in
/home/beep/work/php/hauthd/index.php
on line 20
So it doesn't reacts to any request from extended class.
Last second idea: put spl_autoload_register to each file. But cannot put it to "extends" directive itself!
P.S. May rewrite SqlTool.php using Factory pattern so it would automatically return an instance of project-specifc class, but it seems to be not a best way, or it is..?
If SqlHD extends SqlTool, then your __autoload() function should include this automatically.
Note you have an extra '}' in your filename which is probably messing this up. (Which you have also copy 'n' pasted into your 2nd code snippet.)
{ $fn = "./../shared/{$className}.php}";}
As an aside, I think you only need to require() inside your __autoload() function, rather than require_once(), since your __autoload() function is only called if it has not already been loaded.
[Edit: removed incorrect relative path suggestion - w3d spotted the real problem. Leaving the rest here just for info]
Also you can change the require_once in the autoload function to just require - by definition the function will only run if the class has not already been included.
You could greatly simplify your autoload by utilising the include path, as then PHP would check the different locations for you. E.g. something like this:
set_include_path(
realpath('./specific/php') . PATH_SEPARATOR .
realpath('./../shared') . PATH_SEPARATOR .
get_include_path()
);
function __autoload($className) {
require "$className.php";
}

Categories