__autoload mix up? - php

I have a server with many customers on, when I develop I include my init.php in which I have an __autoloader() function that includes the file with dir_name(__FILE__)."/classes/".$className for instance.
But yesterday I saw that the server could not find the specific class, I restartat apache and then it worked again.
Every customer has this own init.php... ( and therefore many __autoloads on the same server )
customer1/init.php : holds __autoload()
customer1/classes/class.php
customer2/init.php : holds __autoload()
customer2/classes/class.php
I have not done some tests and I hope someone can answer my question before I try to reproduce the problem, but do you think it is possible for php to take the wrong autoload function when you get 2 or more requests at the same time?
Is spl_autoload_register the solution?
Many thanks for some ideas or brainstorming.

My guess is that you should have a typo in either one of your __autoload() functions or you are including the wrong init.php file.
Also, dir_name() does not exist, you should change that to dirname() instead or you can also use the new DIR constant for the same effect if you're using PHP >= 5.3.
EDIT: In light of your comment, use should use:
require(realpath(dirname(__FILE__)) . '/classes/' . $className);
or
require(realpath(__DIR__) . '/classes/' . $className);

Each PHP request is completely separate, in fact it is impossible for you to have two functions named __autoload() in the same PHP request, so they cannot interfere. Possible problems:
You are including the wrong customer's init.php
You forgot to include the init.php file, in which case there is no autoloading at all.

Related

Drupal 7 xautoload composer

So I have the Paypal REST API installed ( https://github.com/paypal/rest-api-sdk-php ) with Composer in my_drupal_module/lib/Drupal/ and now I want to use the namespaces in a function in my module. I understood that I need something like xautoload ( https://drupal.org/project/xautoload ) to do that so I tried something like:
$payer = new \Drupal\vendor\PayPal\Api\Payer;
with and without the first slash, and with and without parentheses at the end but it didn't work. I added:
require DIR . '/lib/Drupal/vendor/autoload.php';
but still nothing so I commented it. Meanwhile I found this: https://drupal.org/node/1976206 that explains this issue but it is unclear to me what exactly to write in hook_xautoload() or direct registration for the setup that I have. Can someone please help?
Nevermind. I solved it. Thanks to proloy03 who gave me the idea: https://drupal.org/node/2096621
You don't need xautoload to load the classes and namespace just implement hook_init to require it like so:
function my_module_init() {
require __DIR__ . '/vendor/autoload.php';
}
and then in your function write:
$payer = new PayPal\Api\Payer();
and it all works.
With xautload you can do something like this...
In mymodule.module
function mymodule_libraries_info() {
'paypal' => array(
'name' => 'PayPal SDK',
'xautoload' => function($adapter) {
$adapter->composerJson('composer.json');
}
}
Declaring this allow you to use the namespace. Like
use PayPal\Api\Amount;
Check xautoload.api.php
Your assumption that you need XAutoload to use the Paypal API installed by Composer is wrong.
The only thing you need to make any code installed by Composer available is to include the Composer autoloader in your code execution path when you need any of the provided classes. The easiest form of this is to simply require the Composer autoloader in the very first index.php (or whatever Drupal uses) file that answers every request (possibly instantiating more Drupal classes, modules and stuff).
Once the code execution comes to your own code, the autoloading allows your code to include all the classes you included with Composer.
How to use the code? Don't invent your own namespace for the existing code, it will not work. "\Drupal\vendor\PayPal\Api\Payer" sounds pretty wrong to me, I suspect the correct namespace is "\PayPal\Api\Payer". And yes, that file does indeed exist. So you have to use that.
If it still does not work, complaining the class could not be loaded, then the Composer autoloader file is not included in your scripts code path.

PHP Functions from included files don't execute on Web Server

I am in the process of migrating a site from my personal dev server onto Windstream's business hosting server. I've already run into the issue of having developed using PHP 5.4 only to find out that my static functions won't work on WS's 5.1.4 installation. I've since fixed those issues and am not facing one that I can't seem to find any help for on the internet.
All of the static functions I was using have been rewritten as functions outside the class scope. Instead of having
class Product{
...
public static function myFunction(){}
...
}
I now have
function myFunction(){}
class Product{...}
in my included Product.php file.
However, when I try to call myFunction() from my code, nothing happens. I know the nothingness comes from WS's error handling, but the point is, the function isn't working. To verify this, I have taken the following steps:
Inserted the line echo "entered included"; immediately following the <?php in Product.php. This prints "entered included" on the index page, indicating that my include is working. I have done the same thing before the final ?> with the same results, so I don't think it's getting hung up inside the included file.
I have changed myFunction() in the included file to be simply
function myFunction(){echo "myFunction works";}
A call to myFunction() still makes nothing happen.
I have moved myFunction() to the including file (myFunction() now lives in index.php instead of Product.php; index includes Product.php). This time, myFunction() executes without issue.
To my 'hack it til it does what it should' sensibilities, this tells me that the server is having a problem with functions that are declared in files that are included; honestly, though, I have absolutely no clue what's going on, and any help would be appreciated. Their website is currently down, and they were expecting it to only be offline for a day, so I'll try pretty much anything short of sacrificing a fatted calf.
I know I should be posting more specific code, but since this is a customer's actual website, I'm trying to put as little of the actual code out here as is possible. I'm happy to append specific sections of code to this entry as they are requested for clarification.
Thanks in advance for your consideration.
#Rottingham: First, thanks for the 3v4l link. Second, my assumption about static methods in 5.4 vs 5.1.4 came from this line of php.net's page on static members and methods:
"As of PHP 5.3.0, it's possible to reference the class using a variable. The variable's value can not be a keyword (e.g. self, parent and static)."
src - http://www.php.net/manual/en/language.oop5.static.php
Since my version and the server version were on different sides of the 5.3 mark mentioned, I incorrectly assumed that this was my problem.
Third, when I get in from my day job, I'll update my code to show errors and update this post if a solution has not yet been found.
Ultimately, my problem isn't with using static methods (since I don't have them anymore) but with using any function that is declared in an included .php file.

Reloading a Class

I have a PHP daemon script running on the command line that can be connected to via telnet etc and be fed commands.
What it does with the command is based on what modules are loaded, which is currently done at the start. (psuedocode below for brevity)
$modules = LoadModules();
StartConnection();
while(true){
ListenForCommands();
}
function LoadModules(){
$modules = Array();
$dir = scandir("modules");
foreach($dir as $folder){
include("modules/".$folder."/".$folder.".php");
$modules[$folder] = new $folder;
}
}
function ListenForCommands(){
if(($command = GetData())!==false){
if(isset($modules[$command])){
$modules[$command]->run();
}
}
}
So, an example module called "bustimes" would be a class called bustimes, living in /modules/bustimes/bustimes.php
This works fine. However, I'd like to make it so modules can be updated on the fly, so as part of ListenForCommands it looks at the filemtime of the module, works out if it's changed, and if so, effectively reloads the class.
This is where the problem comes in, obviously if I include the class file again, it'll error as the class already exists.
All of the ideas I have of how to get around this problem so far are pretty sick and I'd like to avoid doing.
I have a few potential solutions so far, but I'm happy with none of them.
when a module updates, make it in a new namespace and point the reference there
I don't like this option, nor am I sure it can be done (as if I'm right, namespaces have to be defined at the top of the file? That's definitely workaroundable with a file_get_contents(), but I'd prefer to avoid it)
Parsing the PHP file then using runkit-method-redefine to redefine all of the methods.
Anything that involves that kind of parsing is a bad plan.
Instead of including the file, make a copy of the file with everything the same but str_replacing the class name to something with a rand() on the end or similar to make it unique.
Does anyone have any better ideas about how to either a) get around this problem or b) restructure the module system so this problem doesn't occur?
Any advice/ideas/constructive criticism would be extremely welcome!
You should probably load the files on demand in a forked process.
You receive a request
=> fork the main process, include the module and run it.
This will also allow you to run several commands at once, instead of having to wait for each one to run before launching the next.
Fork in php :
http://php.net/manual/en/function.pcntl-fork.php
Tricks with namespaces will fail if module uses external classes (with relative paths in namespace).
Trick with parsing is very dangerous - what if module should keep state? What if not only methods changed, but, for example, name of implemented interface? How it will affect other objects if they have link to instance of reloaded class?
I think #Kethryweryn is something you can try.

PHP Function Scope Failure

I am struggling to understand scope and what's preventing my new code from working (assuming it is a scope issue).
The following function is in a file PATH.'/includes/custom-functions.php' that references a class:
function infusion() {
require_once(PATH.'/classes/infusion.php'); //PATH is defined in WordPress from ~/wp-content/themes/theme/
return new infusion();
}
The class is reliant on PATH.'/api/isdk.php' and connection credentials from another file within /api/ directory. From within PATH .'/includes/custom-functions.php', I have many other functions that call $infusion = infusion(); and work perfectly.
PROBLEM
I have created a new file: PATH.'/includes/report.php' which I need to access $infusion = infusion();but can't get to work by either repeating the function infusion() definition from above; using require_once();; or using include();. All 3 of those options simply kill the rest of the code and I can only come to the conclusion - well, I have no conclusion.
Any help would be greatly appreciated.
I'm assuming the code isn't using namespaces, therefore you aren't permitted to redeclare the infusion function (either by redefining the function, or re-including the class).
Your includes/report.php file should simply have:
require_once PATH.'/includes/custom-functions.php';
// your other code here ...
$infusion = infusion();
It may be the case that other files / classes that you're including in your file are already requiring custom-functions.php along the line, so you may be able to skip that entirely. Also note that the PATH constant should have already been defined somewhere (either directly or via an included file) before you attempt to use it. If you set your error_reporting to include E_ALL, you'll get a notification in your error log if that constant doesn't exist.
If that fails, your error log(s) may provide some additional background on what your issue is.

How Can eval() in This Code Be Not Secure?

I'm using the code below to automatically load and declare classes so that I only need to put class files in a folder named classes. The part in spl_autoload_regsister() may seem to be unnecessary for you but it is needed to work as a WordPress plugin without errors.
It uses eval() and I've seen so many web pages talking about using eval() is bad and can create a security hole. So how could this be dangerous?
$strDirPath = dirname(__FILE__) . '\\classes\\';
$arrClassFiles = array_map(create_function( '$a', 'return basename($a, ".php");' ), glob($strDirPath . '*.php'));
spl_autoload_register(
create_function('$class_name', '
global $arrClassFiles, $strDirPath;
if (in_array($class_name, $arrClassFiles))
include($strDirPath . $class_name . ".php");' )
);
foreach ($arrClassFiles as $strClassName) {
$strClassName_alpha = $strClassName . "_Alpha";
eval("class $strClassName_alpha extends $strClassName {};");
}
print_r(get_declared_classes());
Maybe, somebody can put a file name of php code in the folder? But I don't see it can compromise the system.
If they can name a class file something like randomclass {}; echo $db_password;//.php, then you could have a code execution attack.
I'm pretty sure that's not a valid file name, but there are people far wilier than me at crafting valid malicious inputs.
It's just usually not an attack surface you need to open yourself up to, given that it's practically always possible to avoid with better code structure.
If an error condition is handled, I don't see a problem here.
Just be sure that if someone tries to call a different class that does exist (i.e. code that would be valid here, but that you wouldn't want your hacker to run directly because it would bypass a restriction on your system), that it won't be a security problem - or that it wouldn't be possible to run that class at all from this context.
Just in case, deny any attempts to run code with the words "class," or other keywords, or any built in class names, or built in function names, other builtins, etc. and you should be fine, but even that probably isn't necessary in your particular case here because would probably result in an error.

Categories