PHP not finding function declared in required file - php

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.

Related

Why the "use" command in PHP not working with include?

I have this script:
<?php
error_reporting(E_ALL);
require 'vendor/autoload.php';
use Church\Config;
use Church\SQLiteConnection;
use Church\Template;
use Church\User;
$ERROR = "";
if(isset($_POST['username']) && isset($_POST['username']))
{
$login = new User((new SQLiteConnection())->connect());
if($login->loginUser($_POST['username'], $_POST['password']))
{
}
else {
$ERROR = "login";
}
}
if(isset($_GET['go']))
{
}
else {
if (!file_exists(Config::PATH_TO_SQLITE_FILE)) {
include('init/install.php');
}
}
When I make it with this part:
include('init/install.php');
instead of this:
$tpl = new Template('templates/install.tpl');
$tpl->set('HEADER', $tpl->getFile('templates/header.tpl'));
$tpl->set('FOOTER', $tpl->getFile('templates/footer.tpl'));
$tpl->set('APP_NAME', Config::APP_NAME);
$tpl->set('APP_VERSION', Config::APP_VERSION);
$tpl->set('BASE_URL', $_SERVER['PHP_SELF']);
$tpl->render();
I get this error:
Fatal error: Uncaught Error: Class 'Template' not found in
I do not understand why it is working without include but with include is the auto loading not working. What did I miss?
Take a look at the docs here: https://www.php.net/manual/en/language.namespaces.importing.php
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword:
And then:
Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules.
The conclusion is that you can't do what you want to do. You need to import (aka use) in your included file too.

Cannot load custom content type nodes with load_node_multiple or load_node

I have a custom content type called "program" that I am trying to load via a drupal module.
The .module file includes a class called Program that has a method called
getAllPrograms() using include_once(drupal_get_path('module', 'progs') . '/progs.php');
When i try and load nodes using either node_load() or node_load_multiple() i get one of two different errors randomly.
either:
Fatal error: Fatal error: Call to undefined function user_access() in /mypath/modules/filter/filter.module on line 1035
or
Error: Call to undefined function token_get_entity_mapping() in /mypath//sites/all/modules/contrib/token/token.tokens.inc, line 767
Note: 99% of times it is the first error, and occasionally i would recieve the token_get_entity error.
The strange thing is, while i have been trying different things to resolve the error I have been able to get both of these functions to work for a period but as soon as i clear the Drupal Cache i get the error again.
What I have tried
Disabling and enabling the user module via the database.
Checking the paths and status are correct for the main modules (system, user, block etc)
using db_select to get a list of node ids and then use node_load() (with a loop) and node_load_multiple() to load the nodes. This is one of the things that started working for a short time until i cleared the cache.
Tested to see if i can call user_access() from my .module file. This does not work and returns the same call to undefined function error.
Here is the code that I have (not progs an anonymized name)
progs.module
include_once(drupal_get_path('module', 'progs') . '/progs.php');
progs.php
if( !class_exists('progs') ):
class progs
{
//a bunch of properties
function __construct()
{
// load partial includes and objects
$this->load_partial_inclues();
//retrieve all programs that are open
$this->open_programs = Program::getAllOpenPrograms();
}
function load_partial_inclues()
{
//includes
include_once(drupal_get_path('module', 'progs') . '/core/objects/program.php');
}
}
function progs()
{
global $progs;
if( !isset($progs) )
{
$progs = new progs();
}
return $progs;
}
// initialize
progs();
endif;
Note: I load the $progs into the global space so i can call it elsewhere in my module.
program.php
if( !class_exists('Program') ):
class Program
{
//a bunch of properties
public static function getAllOpenPrograms()
{
// This is the line that causes all of the issues.
$result = node_load_multiple('',array('type' => 'program'));
dpm($result);
}
Thanks in advance!
Like Mike Vranckx mentioned, if you call progs() directly when you include it in progs.module, Drupal basically hasn't bootstrapped, i.e. hasn't started running fully yet. Suggest you put your progs() in progs_init() or similar so that Drupal will invoke it at the right time.
Here's a proposed way that follows your initial structure quite closely, and below you will see an alternative that better follows Drupal's conventions.
New progs.module
/**
* Implements hook_init().
*/
function progs_init(){
progs();
}
And modify your progs.php
// Why are you doing this check? Are you defining this class elsewhere in your project? If not you can safely ignore this
//if( !class_exists('progs') ):
// Convention is to name classes with Pascal case btw.
class progs
{
//a bunch of properties
function __construct()
{
// load partial includes and objects
$this->load_partial_inclues();
//retrieve all programs that are open
$this->open_programs = Program::getAllOpenPrograms();
}
function load_partial_inclues()
{
//includes
include_once(drupal_get_path('module', 'progs') . '/core/objects/program.php');
}
}
function progs()
{
global $progs;
if( !isset($progs) )
{
$progs = new progs();
}
return $progs;
}
A more Drupal way:
progs.module
/**
* Implements hook_init().
*/
function progs_init(){
global $progs;
// Consider using drupal_static to cache this
if( !isset($progs) )
{
module_load_include('inc', 'progs', 'progs');
$progs = new Progs();
}
}
progs.inc (convention is to use .inc)
class Progs
{
//a bunch of properties
function __construct()
{
// load partial includes and objects
$this->load_partial_inclues();
//retrieve all programs that are open
$this->open_programs = Program::getAllOpenPrograms();
}
function load_partial_inclues()
{
//includes
module_load_include('php', 'progs', 'core/objects/program');
}
}

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.

What is the right way to include plugins files in plugin system

I've created a plugins system, and I've created everything in that system except, how can I inclusion plugins files to execute it.
I'm tried to create a method, Which is doing include plugins files to execute it.
-- Firstly -- :
The method that get all plugins files, and that begin with index word which indicates the main file of plugin (i.g. index-pluginName.php), and add the path and file name to an array.
public function getPluginFiles($plugin_folder) {
$dir = opendir($plugin_folder);
while ($files = readdir($dir)) {
if ($files == '.' || $files == '..')
continue;
if (is_dir($plugin_folder.'/'.$files))
$this->getPluginFiles($plugin_folder.'/'.$files);
if (preg_match('/^[index]+/i', $files)) {
$this->plugins_path[$plugin_folder.'/'.$files] = $files;
}
}
closedir($dir);
}
-- secondly -- :
The method that include all the main file of plugins to execute, and this method get the path and name of plugin file from the array that created earlier .
public function includePlugFiles() {
$this->getPluginFiles($this->plugin_folder);
foreach ($this->plugins_path as $dir=>$file) {
include_once (dirname($dir)."/".$file);
}
}
Also see an example of code that exists in plugin file:
function test() {
echo " This is first plugin <br/>";
}
$plugin->addHook('top', test); // parameters(top=position, test=callback)
Now, when I create an instance of the object to be this form .
$plugin = new plugin;
$plugin->includePlugFiles();
But after all this, shows error message
Fatal error: Call to a member function addHook() on a non-object in .... projects\plugins\index-test.php on line 7
This is the code of line 7:
$plugin->addHook('top', test); // parameters(top=position, test=callback)
I know the problem occur because, the object will not be created.
and the problem is can't create the object in every main plugin file.
It's probably not the cleanest solution, but instead of trying to reference the $plugin symbol (which is outside the scope of the plugin file), you could also do this:
$this->addHook('top', test);
Alternatively, you could explicitly create the reference inside the includePlugFiles() method:
public function includePlugFiles()
{
$plugin = $this;
$this->getPluginFiles($this->plugin_folder);
foreach ($this->plugins_path as $dir=>$file) {
include_once (dirname($dir)."/".$file);
}
}

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