Odd PHP Class autoloader Behavior - PEAR Related - php

I have a strange problem I can't figure out. I'm using PEAR to send mail from a PHP page. The Send_Mail class is working (sending mail using SMTP), but I'm getting this strange warning associated with my autoloader.
Warning: include(classes/LOGIN.php)
[<a href='function.include'>function.include</a>]:
failed to open stream: No such file or directory in
C:\xampp\htdocs\mysite\initialize.php on line 46`
In my initialize.php file, I have this:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
And in my header.php file I am loading several PHP classes for the site:
// autoload PHP classes for site
autoloader('Navigation');
autoloader('Validation');
The error referes to a LOGIN class which I don't have. But I searched my entire site folder, including php and found these two lines in C:\xampp\php\PEAR\Net\SMTP.php:
/* These standard authentication methods are always available. */
$this->setAuthMethod('LOGIN', array($this, '_authLogin'), false);
$this->setAuthMethod('PLAIN', array($this, '_authPlain'), false);
When I comment out the line containing LOGIN I get the same warning but for PLAIN and when I comment out both lines, the warnings go away (but then SMTP authentication fails).
Why is this happening?
UPDATE
Here is my new autoloader:
function autoloader($class) {
if (file_exists('classes' . $class . '.php')) {
include 'classes' . $class . '.php';
}
}
When I echo 'classes' . $class . '.php', though, I get this:
classes/.php
And then if I change it back to not use the file_exists it works, but the echo still shows classes/.php

I'm not sure what version of Net_SMTP you're on, but the setAuthMethod function takes as a parameter various different types of structures - method names, classes, objects, callables, etc.
Since PHP is dynamically typed, SMTP.php in Net_SMTP has to do a lot of checking on that object in order to determine what type of object it is. As part of that, it tries to determine if 'LOGIN' is a class name, which is invoking your autoloader.
The solution is to perform a file_exists in your autoloader before trying the include, but of course if your include path is complex in any way you're basically setting yourself up for headaches. Anyone who has dealt with writing a comprehensive autoloader knows your pain.

I reverted back to a simple autoloader and things seem to be working fine:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
Thanks for suggestions.

Related

Magento - loading external php scripts inside controller

Any time I want to load an external library from inside a class conforming to the Magento module approach. I am always faced with the following error:
require_once(): Failed opening required 'http://example.com/HTML2PDF/tcpdf.php'
Despite that the URL is correct. For example:
class Foo_Bar_AccountController extends Mage_Customer_AccountController
{
public function whatever() {
require_once(Mage::getBaseUrl() . 'HTML2PDF/tcpdf.php');
}
}
Can anyone help understand why I cannot include files this way?
I think I may have figured it out. Not sure why, but I believe Magento somehow doesn't allow including files outside your own module. Anyways this seems to work:
require_once Mage::getModuleDir('', 'Foo_Bar'). DS . 'lib' . DS . 'tcpdf_6_2_11' . DS . 'tcpdf.php';
Just by adding a custom folder inside my module and then calling Magento's Mage::getModuleDir method it works!
If anyone can better explain why this happens then it may help others (myself included) understand better.
Thanks
The Mage::getBaseUrl() function is for URLs, not file paths. So, it will return a string starting with "http://". What you want is Mage::getBaseDir('lib').
The solution you provided works, but typically (and arguably) you should be putting third-party / external PHP scripts in the top-level lib folder. That way all third-party libraries are in one place and you don't have to even call Mage::getModuleDir(). Your folder structure would be:
/magento/
app/
code/
local/
Foo/
Bar/
controllers/
AccountController.php
...
lib/
HTML2PDF/
tcpdf.php
And your controller would be:
<?php
class Foo_Bar_AccountController extends Mage_Customer_AccountController
{
public function whatever() {
require_once(Mage::getBaseDir('lib') . DS . 'HTML2PDF/tcpdf.php');
}
}
What's even better is that when you have files in the base lib, they are included in the autoloader's search for classes. So sometimes you can get away with simply instantiating the class, and the autoloader does the work of finding the correct file to require.

Classes/PHPExcel_Shared_String.php): failed to open stream

This question was asked in 2010. I am seeing a related problem but the recommended solutions from 2010 don't fix it.
I am using PHPExcel v 1.8.0 (March 2014)
The suggestions made on the original reply have been incorporated and the rest of the system still works normally, for example I have an init.php file that is brought in for every scrip which includes the following as suggested in an earlier post:
function myAutoload($Class)
{
require_once 'Classes/' . $Class . '.php';
}
spl_autoload_register('myAutoLoad')
All {classes.php} files are in the Classes/ folder off the document root including, of course PHPExcel.php. The PHPExcel folder is also contained in the Classes/ folder.
I have tried various ways of spinning up PHPExcel, including the usual
$spreadsheet = new PHPExcel;
As an alternative I also tried defining a Spreadsheet class
Class Spreadsheet extends PHPExcel {.... }
They all produce the same error as cut and paste into the above
I have successfully ported over the remainder of the processes in the application from a procedural style to object orientated system, and it has been well worth the weeks that have been spent on it. This last hurdle with PHPExcel however has got me foxed!
Any suggestions would be appreciated
Modify your autoloader to return a false if it can't load the specified file:
function myAutoload($Class)
{
if (file_exists('Classes/' . $Class . '.php')) {
require_once 'Classes/' . $Class . '.php';
return true;
}
return false;
}
That way, autoloading will from through your own autoloader and execute the next autoloader in the "queue" (the PHPExcel autoloader) if it doesn't find the requested file through your own autoloader. If you don't return a false the SPL autoloader handler won't bother working through any other "queued" autoloaders

Class not found error even with autoloading

I'm not a PHP expert; am trying to use this TextRank Library to help with a project.
I seem to be running into a bizarre issue: even after adding the autoload function, executing on the command line still results in "class not found" error. So here's the layout:
Code that calls the other classes (the "main" code):
echo realpath (__DIR__);
function __autoload($class_name) {
if(file_exists(__DIR__ . "/lib/TextRank/" . $class_name . '.php')) {
require_once(__DIR__ . "/lib/TextRank/" . $class_name . '.php');
} else {
throw new Exception("Unable to load $class_name.");
}
}
$config = new Config;
$textrank = new TextRank($config);
$keywords = $textrank->getKeywords("The only asynchronous, one-on-four game in Nintendo’s booth came from the “Wait, they’re still making that?” franchise that is Mario Party, and its buried presence didn’t bode well. Thankfully, Mario Party 10’s demo didn’t waste time with the series’ slowest crawl-around-a-board-game moments, instead jumping straight into four mini-games.");
var_dump($keywords);
Here's my directory structure:
/test.php (the above file)
/lib
/lib/TextRank (contains all the classes referenced by the above code
/lib/TextRank/Config.php
Yet, I still get:
Fatal error: Class 'Config' not found in /path/to/test.php
This means that:
The autoload is working, as no exceptions were thrown.
But somehow, PHP still isn't finding the required classes??
Does this have anything to do with the namespace conventions used in the classes, such as:
(in /lib/TextRank/Config.php)
namespace crodas\TextRank;
class Config
{
....
Yes it does. You need to do
$config = new crodas\TextRank\Config();
But that will not get catched by your autoloader. You need to look for an PSR-0 compatible autoloader.

PHP __autoload() with exception handling - waste of time?

I'm a bit new to OOP and I'm working on a 'framework' for my own application. I have my own autoload function which looks like below.. as well as an exception handling object. I won't be using any 3rd party plugins (at least I don't think).
First question: Should I bother with exception handling in my autoload or am I just overdoing things?
Second question: My exceptionHandler class is a public function...since it's something that will be used by many other applications is this the right? Thank you.
Thanks..any input is greatly appreciated.
function __autoload( $class ){
// Define filename pattern to include
$filename = $_SERVER['DOCUMENT_ROOT'] . '/../app/core/models/' . $class . '.class.php';
// Require class if it exists
try {
if ( is_readable( $filename ) ) {
require_once ( $filename );
}
else {
throw new Exception( "Class filename doesn't exist or isn't named correctly: $filename" );
}
}
catch ( Exception $e ) {
// Send to exceptionHandler Class for logging/handling.
$err = new exceptionHandler( $e, 3 );
}
}
Regarding your first question: No, you shouldn't.
First reason: You should always be able to chain multiple autoloaders (see spl_autoload_register), so if one autoloader fails, a second one might be able to load that class. Because of this, your autoloader should not throw any errors unless you know exactly what you're doing.
Second reason: If all autoloading attempts fail, php will trigger an error anyway. Log your php errors properly and you won't need to log this in your autoloader.
Third reason: Your autoloader will be a piece of code that will be executed a lot. You don't want a try/catch block here.
Apart from that: What happens, if autoloading your exceptionHandler fails...?
Any autoload function is really not meant to throw exceptions, because it's not clear where that exception should rise and you would have to either wrap the entire code in a try catch block or define a exception handler.
You should trigger an error via trigger_error or even better let PHP tells you what's the class that is not able to load in the real line where it happens (therefore just ignoring files that doesn't exists).
Also you shouldn't use __autoload but spl_autoload_register.
Thank you for the feedback Jeffrey and Alexander. You guys got me thinking.. I ended up removing my home grown autoloader for an easier (and faster?) method...
In my config file I added the include path for my core application classes as well as the module classes:
set_include_path( get_include_path() . PATH_SEPARATOR . APPLICATION_ROOT . 'core' . DIRECTORY_SEPARATOR . PATH_SEPARATOR . APPLICATION_ROOT . 'module' . DIRECTORY_SEPARATOR );
spl_autoload_extensions( '.class.php' );
spl_autoload_register();
So far it works :)

spl_autoload_register is not initializing autoload stack

I am trying to use the SwiftMailer php library with a program that I wrote. I have been using the spl_autoload_register() function just fine before including this library. However, prior to using this library I was explicitly defining the class extensions and locations using the spl functions:
set_include_path(get_include_path().[my include path]);
spl_autoload_extensions('.class.php');
spl_autoload_register();
session_start();
The problem I'm running into, is that now I'm trying to use a library that does not follow along the same naming conventions. Their own autoload class (built by the initial call to the library) looks like this.
public static function autoload($class)
{
//Don't interfere with other autoloaders
if (0 !== strpos($class, 'Swift_'))
{
return;
}
$path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';
if (!file_exists($path))
{
return;
}
if (self::$initPath && !self::$initialized)
{
self::$initialized = true;
require self::$initPath;
}
require $path;
}
When I try to simply run the program after calling their class I get:
Fatal error: spl_autoload() [<a href='function.spl-autoload'>
function.spl-autoload</a>]:Class Swift_MailTransport could not
be loaded in [my file] on line 30
Line 30:
$transport = Swift_MailTransport::newInstance();
I have tried using a custom autoload class modeled after theirs, however, all I get when I try:
var_dump(spl_autoload_functions());
results:
bool(false);
I know this has to be a fairly simple issue, something that I'm overlooking, but I can't find it.
Any help would be greatly appreciated.
Try removing this:
spl_autoload_register();
From the documentation:
[if] spl_autoload_register() is called without any parameters then
[spl_autoload(...)] functions will be used
Knowing that, it's only logical to think that spl_autoload does not know where to load your SwiftMailer classes because the errors you get say so. It then follows that SwiftMailer is not in your include path because spl_autoload tries to load from there.
Next step is to put your SwiftMailer classes in one of the include paths.
Ok, after knocking my head against the wall all day and getting nowhere, I got a great piece of feedback from my brother who is also a programmer.
The whole problem, stemmed from this one line:
require_once(SITE_ROOT.'/classes/lib/swift_required.php');
The SITE_ROOT variable was actually referencing the web location (i.e. http://), with my current host, this does not work, it needs to use the physical file location instead. After making this change, the included autoloader works as advertised.

Categories