Call script based on variable name - php

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.

Related

'require' work but 'require_once' doesn't work

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.

PHP Require file inside Static Method

In my class I've got a Method, that includes diffrent Files based on the input.
The Files are included correctly => var_dump shows "true".
BUT!! If I want to access the included variable, it tells me, that it's not defined....
The included file:
<?php
$cpucooler = array(
array(
"Name" => "Boxed CPU Lüfter",
"Sockel" => "Alle",
"Leistung" => 20,
"RPM" => 2000,
"Preis" => 0
));
?>
The Class Method:
/**
* Get Hardware for classes
* #param string $type Hardware type
* #return array
*/
public static function getHardware($type) {
switch ($type) {
case 'cpucooler':
require_once "hardware/cpucooler.php";
var_dump($cpucooler); // undefined variable...
return $cpucooler;
break;
}
}
Hope someone can help me
File was correctly included, the Problem was, that I used
require_once $file;
return $cpucooler;
instead of
require $file;
return $cpucooler;
Don't know why...
I get that error when I cannot include the file.
If including works, I also get the data.
In conclusion, since failing to open the file is not a fatal error (just a warning), you probably have disabled outputting warnings, so you don't see them. If you enable error reporting, you should see the warning.
The exact cause of failure is a guess. Maybe the path is incorrect, because you made a typo, or the case of the name is wrong, or the current directory is different from what you think. (try using an absolute path and/or check using the __DIR__ constant.
Make sure that hardware/cpucooler.php is really being included. It's a good practice to use is_file to make sure that you require file that exists in your application.
try {
$filepath = 'hardware/cpucooler.php';
if( ! is_file( $filepath ) ) {
throw new Exception( $filepath . ' do not exists.' );
}
// If exception is thrown, the following code is not executed.
require $filepath;
return $cpucooler;
} catch( Exception $e ) {
echo $e->getMessage();
}

PHP: how to check if a given file has been included() inside a function

I have a PHP file that can be include'd() in various places inside another page. I want to know whether it has been included inside a function. How can I do this? Thanks.
There's a function called debug_backtrace() that will return the current call stack as an array. It feels like a somewhat ugly solution but it'll probably work for most cases:
$allowedFunctions = array('include', 'include_once', 'require', 'require_once');
foreach (debug_backtrace() as $call) {
// ignore calls to include/require
if (isset($call['function']) && !in_array($call['function'], $allowedFunctions)) {
echo 'File has not been included in the top scope.';
exit;
}
}
You can set a variable in the included file and check for that variable in your functions:
include.php:
$included = true;
anotherfile.php:
function whatever() {
global $included;
if (isset($included)) {
// It has been included.
}
}
whatever();
You can check if the file is in the array returned by get_included_files(). (Note that list elements are full pathnames.) To see if inclusion occurred during a particular function call, check get_included_files before and after the function call.

PHP not finding function declared in required file

Recently downloaded some code for a minor open-source project related to a small webgame I play. Trying to access it fails and spits out an error message of:
PHP Fatal error: Call to undefined function v() in /Applications/MAMP/htdocs/infocenter/modules/security_mod.php on line 7
After searching, I found that the function v() is defined in a file called "system.php" which is required by a file which is required by a file which is required by the "security_mod.php" file that the error occurs in. No errors occur with any of the require calls (and they're all 'require_once', not an 'include').
This is the whole of the system.php file:
<?php
function v($a, $i)
{
return isset($a[$i]) ? $a[$i] : null;
}
?>
This is the function in 'security_mod.php' that throws the error (also including the require calls):
<?php
require_once("settings_mod.php");
require_once("account_mod.php");//this file requires base_mod.php, which requires system.php
class SecurityMod {
public static function checkLogin() {
$name = v($_REQUEST, "acc");//this is the line that causes the error
$password = v($_REQUEST, "pwd");
if (!isset($name) || !isset($password)) {
return null;
}
$acc = AccountMod::getAccount($name);
if (SettingsMod::USE_ENCRYPTED_PASSWORDS) {
if (is_null($acc) || $acc->getPassword() != md5($password)) {
return null;
} else
return $acc;
} else {
if (is_null($acc) || $acc->getPassword() != $password) {
return null;
} else
return $acc;
}
}
?>
I did a little testing, and found out that I can access variables and functions in some of the other required files. All of those are in classes, though, unlike v(). Would that be the reason?
EDIT to clarify how 'system.php' is required:
'security_mod.php' has these two require_once calls at the beginning of the file:
require_once("settings_mod.php");
require_once("account_mod.php");
'settings_mod.php' is a file containing constants used through the program, and includes no files.
'account_mod.php' has these two require_once calls:
require_once("base_mod.php");
require_once("account.php");
'account.php' has a pair of include_once calls that include inconsequential and unrelated files.
'base_mod.php' is the file with the ultimate requirement for 'system.php':
require_once("system.php");
require_once("settings_mod.php");
Found the issue: the System.php file being successfully included wasn't the same as the one in the downloaded code. Since base_mod.php only provided a filename, not a path, PHP first checked in the directory specified by my include_path, which turns out to contain a file named System.php. Since my filesystem is case-insensitive, that was judged to be the same as system.php, and therefore got included instead.

File private variables in PHP

Is it possible to define private variables in a PHP script so these variables are only visible in this single PHP script and nowhere else? I want to have an include file which does something without polluting the global namespace. It must work with PHP 5.2 so PHP namespaces are not an option. And no OOP is used here so I'm not searching for private class members. I'm searching for "somewhat-global" variables which are global in the current script but nowhere else.
In C I could do it with the static keyword but is there something similar in PHP?
Here is a short example of a "common.php" script:
$dir = dirname(__FILE__);
set_include_path($dir . PATH_SEPARATOR . get_include_path());
// Do more stuff with the $dir variable
When I include this file in some script then the $dir variable is visible in all other scripts as well and I don't want that. So how can I prevent this?
There are a few things you could do to keep $dir out of subsequent files
Example 1
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
This is the most obvious.
Example 2
$dir = dirname(__FILE__);
set_include_path($dir . PATH_SEPARATOR . get_include_path());
// work with $dir
unset($dir);
Just unset the variable after defining it and using it. Note this will unset any variable named $dir used prior to including this script.
Example 3
define('DIR_THIS', dirname(__FILE__));
set_include_path(DIR_THIS . PATH_SEPARATOR . get_include_path());
It is less likely I suppose to redefine a global constant like this.
Example 4
function my_set_include_path {
$dir = dirname(__FILE__);
set_include_path($dir . PATH_SEPARATOR . get_include_path());
// Do more stuff with the $dir variable
$my_other_var = 'is trapped within this function';
}
my_set_include_path();
You can define as many variables within that function and not affect the global namespace.
Conclusion
The first method is the easiest way to solve this problem, however because you want to use $dir again, it may not be ideal. The last example will at least keep that $dir (and any others defined in that function) out of the global namespace.
The only way you're going to accomplish anything close to what you want is to wrap everything in that included file in a function, and call it. If the file needs to execute itself you could still do
<?php
run_myfile()
function run_myfile() {
...
}
?>
There is no generic way to make a variable scoped to only a file outside of namespaces, classes, or functions.
Well, I'm probably getting flailed for this, but you if you are totally desperate you could use a Registry for that. I've whipped up a small one that does without classes (since I assume from And no OOP is used here so I'm not searching for private class members. means you don't want to do it with OOP at all)
function &registry_get_instance()
{
static $data = array();
return $data;
}
The static $data variable inside is persisted inside the function scope, so you can call the function wherever you like and always get the same contents. The crucial point is returning by reference, e.g.
$registry = &registry_get_instance(); // get $data array by reference
$registry['foo'] = 'bar'; // set something to $data
unset($registry); // delete global reference to $data
print_r(&registry_get_instance()); // show $data
Obviously you'd still have $registry as a variable in the global scope when calling this method from the global scope. So, you could add some more functions to make the Registry more convenient to use, e.g. for setting data to the Registry:
function registry_set($key, $value)
{
$registry = &registry_get_instance();
$registry[$key] = $value;
}
and for getting it out again:
function registry_get($key)
{
$registry = &registry_get_instance();
if(array_key_exists($key, $registry)) {
return $registry[$key];
} else {
trigger_error(sprintf(
'Undefined Index: %s', htmlentities($key)
), E_USER_NOTICE);
}
}
and for checking if a key exists:
function registry_isset($key)
{
$registry = &registry_get_instance();
return array_key_exists($key, $registry);
}
which you could then use like:
registry_set('foo', 'bar'); // setting something to the registry
var_dump( registry_isset('foo') ); // check foo is in the registry now
echo registry_get('foo'); // prints 'bar'
echo registry_get('punt'); // raises Notice
You could populate the Registry from an include file with an additional method like this:
function registry_load_file($file)
{
if(!is_readable(realpath($file))) {
return trigger_error(sprintf(
'File is not readable: %s', htmlentities($file)
), E_USER_WARNING);
}
$config = include $file;
if(!is_array($config)) {
return trigger_error(sprintf(
'Expected file %s to return an array', htmlentities($file))
, E_USER_WARNING);
}
$registry = &registry_get_instance();
$registry += $config;
}
with the include file having to return an array:
// config.php
return array(
'setting1' => 'something'
);
and then you can do
registry_load_from_file('config.php'); // add the contents of config to registry
print_r(registry_get_instance()); // show content of registry
Of course, this is now six functions in the global scope just for not having a global variable. Don't know if it's worth it, especially since I consider static in functions and all that reference stuff doubtful practice.
Take it as a proof of concept :)
Why not just put everything in a static class? Then you only have a single "variable" that could possibly conflict with the global namespace.
class MyClass {
public static $myvar = 1;
public static $myvar2 = "xyz";
public static function myfunction() {
self::$myvar++;
self::$myvar2 = "abc";
}
}
// References to class items, if needed
MyClass::myfunction();
MyClass::$myvar += 3;
If the problem you are trying to is just:
$dir = dirname(__FILE__);
set_include_path($dir . PATH_SEPARATOR . get_include_path());
// Do more stuff with the $dir variable
Then the solution would be to change the include path relative to '.' in your ini settings. E.g. change:
include_path=includes:/usr/local/php
to
include_path=./includes:/usr/local/php
Note that a script does not come into scope except where you explicitly include/require it (both the _once check applies globally) however I would recommend strongly against calling include/require from within a function - its much more transparent having the includes/requires at the top of the script.
I think that the problem you are trying to solve is based on a false premise and you should look for another way of fixing it. If you want the code in an include file to behave differently depending on what includes it, then really you should seperate it out into 2 seperate files - or maybe even 3 - 2 for the different behaviours and 1 for the common.
C.

Categories