'require' work but 'require_once' doesn't work - php

When I use require_once or include_once to include a file it does not work, while when I use require or include it works fine.
public function ParseURL() {
require_once (APP_PATH . "config/config.php");
$this->url_as_parts = explode('/', $this->url);
$class = isset($this->url_as_parts[0]) ? $this->url_as_parts[0] : $config['default_controller'];
$method = isset($this->url_as_parts[1]) ? $this->url_as_parts[1] : "index";
$parms = isset($this->url_as_parts[2]) ? $this->url_as_parts[2] : "";
if (!class_exists($class)) {
trigger_error("The class {$class} not exists <br/>");
exit;
}
$controller = Object::get($class);
if (!method_exists($controller, $method)) {
header('HTTP/1.0 404 Not Found');
include(SYSTEM_PATH . "languages/" . $config['system_language'] . "/errors/404_not_found.html");
exit;
}
if (empty($parms)) {
$controller->{$method}();
} else {
$parms_array = array_slice($this->url_as_parts, 2);
call_user_func_array(array($controller, $method), $parms_array);
}
}
The following line does not produce an error and the path is correct
require_once (APP_PATH . "config/config.php"); but I cant access $config['system_language'] which is inside the file config.php.
Note that when I change the require_once to require or include, everything is OK.

As comes from require_once description - file required only once
Any other require_once of this file will not work.
And you obviously run you function ParseURL more than once. So, your require_once not working on second and consecutive calls.
So, you can use just require or, as I see this is part of a class, create, for example, a wrapper method which will assign config data to your class variable. I.e:
public function getConfig()
{
$this->config = require_once('FILE');
}
In this case your config file should return array or object of config variables.

Can it be that something else includes config/config.php, and then redefines/overwrites the variable $config?
The difference between require_once() and is regular counterparts (include() etc) is that require_once() only includes (and executes, if applicable) something if it hasn't been included before.

This might be because you are already loading config/config.php somewhere before in your code.
Calling require_once(APP_PATH . "config/config.php"); checks that the file config.php already is included and hence does not include it inside that function.
That is the reason your function does not have access to $config variable.
Hope that helps.

Related

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

How can I make a require_once header file in php to be used inside functions?

Can I set it as a global variable like:
<?php
$GLOBALS['dbconnect'] = require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR.'/location/file.php');
$short = $GLOBALS['dbconnect'];
function someFunction() {
echo $short;
}
?>
I am using a database connection file twice, once outside of a function, and once inside a function. The query inside the function can't run because the credentials, servername, db, etc.. are not defined.
I'm not sure how this works?
When I place the require_once file inside the brackets, nothing happens, page is white.
This is the first example from link
<?php
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
If you don't want to use an auto loader for whatever reason you can do the following. Have a file called config.php at the root of your project and have it contain this code.
<?php
// Replaced the \ which appear on localhost to / so it works online.
define("BASE_DIR", str_replace("\\", "/", __DIR__));
$files = [
BASE_DIR . "/path/to/my/file.php"
];
function loadFiles()
{
foreach ($files as $file) {
require_once $file;
}
}
?>
Then in your other files include the config file and call loadFiles. This is essentially an autoloader but sometimes it can be hard to grasp so you can use this.

Call script based on variable name

I have a parent function that is passed a variable called $scriptName. Depending on what is stored in $scriptName, I want to call the corresponding script.
I have a file called childOneScript.php
If $scriptName=="childOne", how do I call childOneScript.php?
You can just use the normal require
require_once $scriptName . 'Script.php';
Keep in mind however that if the script does not exist PHP will raise a fatal error, so you should be checking that the script does indeed exist.
/**
Assumes that $name does not contain the PHP extension and
this function works with relative paths.
If the file does not exist, returns false, true otherwise
*/
function loadScript($name) {
$name = $name . '.php';
if (!file_exists($name) || !is_readable($name)) {
// raise an error, throw an exception, return false, it's up to you
return false;
}
require_once $name;
return true;
}
$loaded = loadScript('childOneScript');
Alternatively you can use include, PHP will only raise a warning if it can't find the script.
There are a few security concerns with the above function. For example if the user is allowed to define the value of $scriptName an attacker could use it to read any file that is readable to the web server user.
Here is an alternative that limits the number of files that can be dynamically loaded to just the files that need be loaded in this manner.
class ScriptLoader {
private static $whiteList = array(
// these files must exist and be readable and should only include
// the files that need to be loaded dynamically by your application
'/path/to/script1.php' => 1,
'/path/to/script2.php' => 1,
);
private function __construct() {}
public static function load($name) {
$name = $name . '.php';
if (isset(self::$whiteList[$name])) {
require_once $name;
return true;
}
// the file is not allowed to be loaded dynamically
return false;
}
}
// You can call the static method like so.
ScriptLoader::load('/path/to/script1'); // returns true
ScriptLoader::load('/path/to/script2'); // returns true
ScriptLoader::load('/some/other/phpfile'); // returns false
You can simply do:
if ($scriptName=="childOne"){
require_once(childOneScript.php);
}
The require_once statement will check if the file has already been included, and if so, not include (require) it again.
Readup: require_once() | PHP
Just use the include statement inside the If condition.
if $scriptName == "childOne" {
include childOneScript.php;
}
You could use the include or require methods in PHP
<?php
function loadScript($scriptName) {
if ($scriptName=="childOne") {
include("childOneScript.php");
}
}
?>
Keep in mind though that the included script is included where you load it. So it's inside the loadScript function. That means you cannot access it's content outside its scope.

Using include_once and include

Sometime I have to use include_once and include it depend how the page are accessed. For example:
sales.php
include("class/pdoDatabase.php");
include("class/ClassExample.php");
$obj = new ClassExample();
$obj->getNewItem(1);
ClassExample.php
include_once("class/pdoDatabase.php");
class ClassExample {
public function getNewItem($id) { .. }
public function addNew($id) { .. }
}
// Accessing this file directly via Ajax request
if (isset($_POST['AddNew'])) {
$obj = new ClassExample ();
$obj->addNew($_POST['id']);
}
}
If you access to sales.php which will then load include("class/ClassExample.php");, however I have to use include_once in the ClassExample.php because pdoDatabase.php might be already loaded in sales.php.
If you access the file directly to ClassExample.php with POST query, it mean it will have to load the file and create an object.
Problem:
Problem is when you access to ClassExample.php directly - it could not find class/pdoDatabase.php . It work fine when sales.php load class/pdoDatabase.php file
This is not a problem with include_once and include difference. This is a problem with relative paths. Include always uses paths relative to called php file. You have this file structure:
sales.php
[class]
- pdoDatabase.php
- ClassExample.php
when you call sales.php everything is ok, but when you call ClassExample.php it's trying to find class/class/pdoDatabase.php which don't exist.
Change include line in your ClassExample.php
include_once(dirname(__FILE__)."/pdoDatabase.php");
and use the same pattern everywhere.
You are doing it wrong.
Instead of manually loading each class file, you should be using autoloader, that you initialize in bootstrap stage of your application. Something along the lines of:
$root = __DIR__;
spl_autoload_register(function( $className ) use ( $root ){
$className = str_replace( '\\', '/', $className );
$filepath = $root . '/' . strtolower( $className ) . '.php';
if ( !file_exists($filepath) )
{
return false;
}
require $filepath;
return true;
});
To learn more about this, please read about spl_autoload_register() in the manual.

what is the usage of `spl_autoload_extension() `with `spl_autoload_register()`?

I am using spl_autoload_register() function to include all files . What i want that any class having extension .class.php or .php would includes directly. I made below class and register two different function and everything working fine, BUT
I think there is some way so that i need to register only one function to include both extensions together.
please have a look on my function and tell me what i am missing
my folder structure
project
-classes
-alpha.class.php
-beta.class.php
-otherclass.php
-includes
- autoload.php
-config.inc.php // define CLASS_DIR and include 'autoload.php'
autoload.php
var_dump(__DIR__); // 'D:\xampp\htdocs\myproject\includes'
var_dump(CLASS_DIR); // 'D:/xampp/htdocs/myproject/classes/'
spl_autoload_register(null, false);
spl_autoload_extensions(".php, .class.php"); // no use for now
/*** class Loader ***/
class AL
{
public static function autoload($class)
{
$filename = strtolower($class) . '.php';
$filepath = CLASS_DIR.$filename;
if(is_readable($filepath)){
include_once $filepath;
}
// else {
// trigger_error("The class file was not found!", E_USER_ERROR);
// }
}
public static function classLoader($class)
{
$filename = strtolower($class) . '.class.php';
$filepath = CLASS_DIR . $filename;
if(is_readable($filepath)){
include_once $filepath;
}
}
}
spl_autoload_register('AL::autoload');
spl_autoload_register('AL::classLoader');
Note : there is no effect on line spl_autoload_extensions(); . why?
i also read this blog but did not understand how to implement.
There is nothing wrong with the way you do it. Two distinctive autoloaders for two kinds of class files are fine, but I would give them slightly more descriptive names ;)
Note : there is no effect on line spl_autoload_extensions(); . why?
This only affects the builtin-autoloading spl_autoload().
Maybe it's easier to use a single loader after all
public static function autoload($class)
{
if (is_readable(CLASS_DIR.strtolower($class) . '.php')) {
include_once CLASS_DIR.strtolower($class) . '.php';
} else if (is_readable(CLASS_DIR.strtolower($class) . '.class.php')) {
include_once CLASS_DIR.strtolower($class) . '.class.php';
}
}
You may also omit the whole class
spl_autoload_register(function($class) {
if (is_readable(CLASS_DIR.strtolower($class) . '.php')) {
include_once CLASS_DIR.strtolower($class) . '.php';
} else if (is_readable(CLASS_DIR.strtolower($class) . '.class.php')) {
include_once CLASS_DIR.strtolower($class) . '.class.php';
}
});
Maybe this will help:
http://php.net/manual/de/function.spl-autoload-extensions.php
Jeremy Cook 03-Sep-2010 06:46
A quick note for anyone using this function to add their own autoload
extensions. I found that if I included a space in between the
different extensions (i.e. '.php, .class.php') the function would not
work. To get it to work I had to remove the spaces between the
extensions (ie. '.php,.class.php'). This was tested in PHP 5.3.3 on
Windows and I'm using spl_autoload_register() without adding any
custom autoload functions.
Hope that helps somebody.

Categories