PHP Require file inside Static Method - php

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();
}

Related

How to remove a directory in wordpress using Filesystem_API

I am using WordPress 4.8.1
I am trying to remove a directory from theme setting, but neither getting any error nor any success.
Even PHP error log has not logged data about it, My WP_DEBUG is on.
$wp_filesystem_base = WP_Filesystem_Base();
$wp_filesystem_base->rmdir(dirname($file_path), true);
The class is not undefined for sure as I could have got some error, still I used a class_exists to check it and it is available where I am using.
please let me know, if I am doing it wrong or need any thing more about the issue.
Since a WordPress' core methods working answer is missing here, I propose this complete solution that sums up all the other aswers.
require_once ( ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php' );
require_once ( ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php' );
$fileSystemDirect = new WP_Filesystem_Direct(false);
$fileSystemDirect->rmdir($dir, true);
Summary:
You can't use WP_Filesystem_Base because does not really implement the method rmdir; it's just an interface.
You must require class-wp-filesystem-base.php because it's a dependency of WP_Filesystem_Direct
You can always use your own rrmdir as someone proposed, but you don't have to add additional code to be maintained when a feature is already available in core;
The false argument passed to the constructor is just because the $arg param is needed but not used as explained in official WP's documentation.
I guess you need to use WP_Filesystem_Direct class
WP_Filesystem_Base::rmdir implementation:
public function rmdir( $path, $recursive = false ) {
return false;
}
You can see, that this code is not working with real FS :)
So, WP_Filesystem_Direct::rmdir actually do the job.
I got it to work like this:
/**
* Deletes a directory, using the WordPress Filesystem API
*
* #param string $path
* #return void
* #author Rasso Hilber <mail#rassohilber.com>
*/
function delete_directory(string $path) {
// make it work from the frontend, as well
require_once ABSPATH . 'wp-admin/includes/file.php';
// this variable will hold the selected filesystem class
global $wp_filesystem;
// this function selects the appropriate filesystem class
WP_Filesystem();
// finally, you can call the 'delete' function on the selected class,
// which is now stored in the global '$wp_filesystem'
$wp_filesystem->delete($path, true);
}
Finally I ended with using a core php function, I believe it is a workaround, but will be useful for someone for who the above code or
$wp_filesystem_direct = WP_Filesystem_Direct();
$wp_filesystem_direct->rmdir(dirname($file_path), true);
will not work. You can use this
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir."/".$object) == "dir") self::rrmdir($dir."/".$object); else unlink($dir."/".$object);
}
}
reset($objects);
rmdir($dir);
}
}
This works for me:
require_once ( ABSPATH . '\wp-admin\includes\class-wp-filesystem-direct.php' );
$fileSystemDirect = new WP_Filesystem_Direct(false);
$fileSystemDirect->rmdir($dir, true);
Or simply:
WP_Filesystem();
global $wp_filesystem;
$wp_filesystem->rmdir($dir, true);

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.

Is it wrong to use the return statement this way?

I've got this autoloader method which is used to include class files as needed.
public static function autoloader($className) {
$fileExists = false;
foreach(array(LIBS_PATH, CONTROLLERS_PATH, MODELS_PATH) as $path) {
// Check if the class file exists and is readable
if(is_readable($classPath = $path . '/' . $className . '.php')) {
// Include the file
require($classPath);
$fileExists = true;
break;
}
}
if($fileExists === false) {
exit('The application cannot continue as it is not able to locate a required class.');
}
}
That works fine but I was thinking is this way better:
public static function autoloader($className) {
foreach(array(LIBS_PATH, CONTROLLERS_PATH, MODELS_PATH) as $path) {
// Check if the class file exists and is readable
if(is_readable($classPath = $path . '/' . $className . '.php')) {
// Include the file
require($classPath);
return;
}
}
exit('The application cannot continue as it is not able to locate a required class.');
}
As you can see I'm using the return statement in the middle of the loop to terminate the rest of the function because the class file has been included and the method has done its job.
Which way is the best way to break out of the loop if a match has been found? I'm just unsure about using the return statement because I always associated that with returning some value from a method.
Return can be used to simply break out of a method/function, and this use is perfectly legal. The real question to ask is what impact do you feel it has on readability?
There are different schools of thought on early returns.
One school maintains a single entry/exit point, stating that it makes the code easier to read since one can be assured that logic at the bottom of the code will be reached.
Another school states that the first school is outdated, and this is not as pressing a concern, especially if one maintains shorter method/function lengths.
A medium exists between the two where a trade-off between an early return and convoluted logic is present.
It comes down to your judgment.
No, it is not wrong to use return this way.
At least look at manual:
http://php.net/manual/en/function.autoload.php
void __autoload ( string $class )
void means that it should not return anything.
But it is not an error.
And also better use require_once when including class definitions.

PHP does not instantiate the class after including a file containing it

Here is my problem. I have one file (say, func.inc.php) with autoloader function, registered by spl_autoload_register():
function autoloaderFnc($class) {
global $__CONFIG;
$original = $class_name;
$class_name = mb_strtolower ( $class_name );
foreach ( $__CONFIG ['include_dirs'] as $path ) {
if(file_exists ( $__CONFIG ['root'] . $path . $class_name . '.inc.php' )) {
require ($__CONFIG ['root'] . $path . $class_name . '.inc.php');
$classFound = TRUE;
$foundAt = $__CONFIG ['root'] . $path . $class_name . '.inc.php';
break;
}
}
if( $classFound ) {
if ( class_exists( $original ) ) {
return true;
} else {
$backtrace = debug_backtrace();
$error = "PHP User error: Cannot load class <b>$original</b> included at " . $backtrace[1]['file'] . ":" . $backtrace[1]['line'] . " (searching for <i>$class_name.inc.php</i>), but following file was included: $foundAt";
error_log( $error );
return false;
}
} else {
$backtrace = debug_backtrace();
$error = "PHP User error: Cannot find file with class <b>$original</b> included at " . $backtrace[1]['file'] . ":" . $backtrace[1]['line'] . " (searching for <i>$class_name.model.php</i> and <i>$class_name.inc.php</i>) in none of the following include dirs:<br />" . join ( '<br />', $__CONFIG ['include_dirs'] );
error_log( $error );
}
}
spl_autoload_register('autoloaderFnc');
Then I have a second file (show_me_poi.php), calling some class:
POI::doSmth();
Everything seems OK, but sometimes (and only sometimes!) I receive a following error in log:
[error] PHP User error: Cannot load class POI included at /path_to_dir/php/generators/export.generator.php:156 (searching for poi.inc.php), but following file was included: /path_to_dir/php/scripts/php/incs/poi.inc.php
This is weird, because class POI is defined in properly included file! And I repeat, this situation happens only sometime (10 out of 100 I think). What can cause such behaviour? And how can I fix it?
Thanks in advance!
I've run into this problem as well and I found a solution for my case.
In my situation I had a custom session handler as well which wrote data to the database when closing the session.
When an error occurred the error handler would fire and the error would be handled normally.
But then the session close handler would run and it would encounter and error when trying to write to the database which caused catch statement to fire which, depending on the type of SQL error would throw an Exception of a certain type, but those classes had to be autoloaded. At that point (in a session close handler) you can no longer autoload classes apparently.
Check when this is happening. During normal PHP execution, or in some 'special' PHP mode such as a session handler or a while doing error handling?
The solution in my case was to add class_exists("MyClass", true) before trying to use it. I could throw a normal Exception instead. The Exception will still 'Fatal' as there is nothing left to catch it, but at least it will show the real Exception and not the autoload error.
The problem seems to arise only with APC op-cache turned on. I think that __autoload function can't work properly with caches in some cases. AFAIS only some PHP and APC versions are not compatible with each other.

Do all variables in methods need to be object properties? (PHP)

I'm learning OO PHP and am trying to get some of the coding practices straight. Here is a pared down version of some code I'm using for error (and exception) handling:
final class MyErrorExceptionHandler {
private $level = array(); // error levels to be handled as standard errors
private $path = array(); // full path to file
private $path_short; // filename plus working dir
public function myErrorHandler($severity, $message, $file, $line) {
if (error_reporting() & $severity) { // error code is included in error_reporting
$this->level = array(E_WARNING => 'warning',
E_NOTICE => 'notice',
E_USER_WARNING => 'user warning',
E_USER_NOTICE => 'user notice');
if (array_key_exists($severity, $this->level)) { // handle as standard error
/*$this->severity = $severity;
$this->message = $message;
$this->file = $file;
$this->line = $line;*/
$this->printMessage($severity, $message, $file, $line);
} else { // fatal: E_USER_ERROR or E_RECOVERABLE_ERROR use php's ErrorException converter
throw new ErrorException($message, 0, $severity, $file, $line);
}
}
} // fn myErrorHandler
private function printMessage($severity, $message, $file, $line) {
echo ucfirst($this->level[$severity]) . ': ' . $message;
$this->shortenPath($file);
echo ' in ' . $this->path_short . ' on line ' . $line;
} // fn printMessage
private function shortenPath($file) {
$this->path_short = $file;
$this->path = explode(DIRECTORY_SEPARATOR, $file);
if (count($this->path) > 2) { // shorten path to one dir, if more than one dir
$this->path_short = array_pop($this->path); // filename
$this->path_short = end($this->path) . DIRECTORY_SEPARATOR . $this->path_short; // dir+file
}
} // fn shortenPath
} // cl MyErrorExceptionHandler
The title of this question is probably a little bit off because I'm not 100% on the terminology. Basically I'm trying to figure out a few things.
Is it right to explicitly declare $level and $path as arrays?
Should $level be declared as it is (and made $this->level)? If so, have I assigned its value (E_WARNING etc.) in a wise place? Would the constructor (not shown here) be a smarter choice?
Note the commented block in myErrorHandler(). Originally I had declared all of these properties at the top of the class, and then called $this->printMessage() without any parameters. Which is the more correct way? If I keep the code as is, would I want to then use $this->severity = $severity etc. inside printMessage()?
So, would it be better to:
replace
$this->shortenPath($file);
echo ' in ' . $this->path_short . ' on line ' . $line;
with
$path_short = $this->shortenPath($file);
echo ' in ' . $path_short . ' on line ' . $line;
ultimately, and give a return value in shortenPath()?
I realize this is a mishmash of several different questions, but what I'm trying to get at is a common inquiry about the proper style of declaring/using variables/properties, specifically when dealing with methods.
To summarize: When should I use $this->foo = $foo?
EDIT: sorry, I have assumed below that you would create a new instance of the 'object' with each error which obviously you are not doing. Just edited my answer to reflect this.
"When should I use $this->foo = $foo?"
There can be several cases in which you would do this, but it's usually if you create $foo within a method and wish to have that then accessed by the entire object.
For example, if you wanted to call on an object and use that within this particular object (if it doesn't make sense to extend). You would do something like:
$foo = new DataModel();
$this->foo = $foo;
OR
$this->foo = new DataModel();
That object may be a decorator or something else related to error handling and the above code would usually feature in your constructor. You could then access the methods of that object any time by using:
$this->foo->objectMethod();
..and to express something noted in the comments to this answer:
"would you assign $file to the object as that is used in several methods?"
I wouldn't assign $file to the object,
here's why. The semantics of the word
"property" means "belongs to". In your
case, your class is a error handler.
$file doesn't belong to the error
handler, it belongs to an error
instance. If your class was
MyErrorHandler_Error (created for each
instance of a triggered error), then
$file would be a property of that
class, along with $line and $level.
To answer what I can from your other questions:
It's neither. I would consider it preference.
Yes - any variables or values which should be available to your entire object and required for the object to run properly, should probably be set within your constructor, if not within your variable declarations (not sure of terminology there) at the top of the class.
read the comments below. Because this particular class deals with multiple instances of errors - assigning the properties of those errors to the object wouldn't be best practice as you will be overwriting them with each new error. However, it does make sense to store all of your errors and error properties within an array assigned to the object if you require to access historical data. For example, at the moment, if you create a new error - that is all you are doing. You have no way of accessing any old errors this object has created.
see above
You should also think about conflicts when assigning properties to objects. Are you likely to reassign, because if so, the old property will be gone. Fairly simple but still something you have to consider.

Categories