integrate PHPExcel withe ZendFramework 2 - php

I try to use both libraries PHPWord and PHPExcel as two libraries in ZendFramework2
that is to say put them in /lib of Zend Framework 2 and load them into my controller with
in my autoload.php i put the following
<?php
// autoload.php generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit689ffe38af096b92264c8f237441d64e::getLoader();
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->autoloadernamespaces[] = "Excel_";
$loader->registerNamespace('Excel_');
$loader->setFallbackAutoloader(true);
if ($configSection == 'development')
{
$loader->suppressNotFoundWarnings(false);
}
my Controller is :
<?php
namespace Auth\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Excel\PHPExcel;
class AuthController extends AbstractActionController
{
public function LoginAction()
{
$objPHPExcel = new PHPExcel_Reader_Excel5();
$document = $objPHPExcel->load('example1.xls');
echo date('H:i:s') , " Données Ajoutées Avec Succés" ;
$document->setActiveSheetIndex(0)
->setCellValue('A1', 'Mike')
->setCellValue('D2', 'Spils);
// Save Excel5 file
$objWriter = PHPExcel_IOFactory::createWriter($document, 'Excel5');
$objWriter->save(str_replace('.php', '.xls', __FILE__));
}
}
`
but the classe is not being load
i get the following error
( ! ) Fatal error: Class 'Auth\Controller\PHPExcel_Reader_Excel5' not found in C:\wamp\www\zend\module\Auth\src\Auth\Controller\AuthController.php on line 14
any one can help me pleeeeaase ?

If you are using composer to load zendframework, try to load phpExcel lib too using composer.php.
Run following command from command line in project folder:
php composer.phar selfupdate
php composer.phar require phpoffice/phpexcel
Access in controller method as:
$excelObj = new \PHPExcel();
It works for me.

If you use the "classic" Skeleton
Download the library (in MyApp/vendor/library/ for example)
The website is : http://phpexcel.codeplex.com/
The architecture of PHPExcel is made with prefixes (like zf1), so for me, it's easier to use the "Zend\Loader\ClassMapAutoloader" like this :
modify the file autoload_classmap of your module
<?php
return array('PHPExcel'=>__DIR__.'/../../vendor/library/PhpExcel/PHPExcel.php',);
And so you can use :
$excel = new \PHPExcel();

I don't yet have any experience with ZF2. But I am pretty sure you're registering a wrong namespace, it should be:
$loader->autoloadernamespaces[] = "PHPExcel_";
$loader->registerNamespace('PHPExcel_');
EDIT
Do you have your PHPExcel library in Zend/Excel/PHPExcel at this location?
Well again I am not sure but, it shouldn't be placed inside Zend's core library.
use PHPExcel\Reader\Excel5;
It should be placed parallel to Zend's library perhaps.
- Zend/
- PHPExcel/
EDIT 2
If this is how Zendframework 2 folder structure is:
- vendor/
- zendframework/zendframework/library/Zend
- PHPExcel/
- autoload.php
Perhaps this should be the location to have your PHPExcel library I think

As suggested by #ro-ko, you should place the folder in vendor, so
vendor/PHPExcel
Then open up vendor/composer/autoload_namespaces.php
You'll see something like this
<?php
// autoload_namespaces.php generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Zend\\' => $vendorDir . '/zendframework/zendframework/library/',
'ZendTest\\' => $vendorDir . '/zendframework/zendframework/tests/',
);
Simply add you namespace and the path to that array, eg...
return array(
'Zend\\' => $vendorDir . '/zendframework/zendframework/library/',
'ZendTest\\' => $vendorDir . '/zendframework/zendframework/tests/',
'PHPExcel\\' => $vendorDir . '/PHPExcel/',
);

This is what solved my problem in ZF2.
Added this to
/vendor/composer/autoload_namespaces:
'PHPExcel' => array($vendorDir . '/zendframework/zendframework/library/Zend/PHPExcel/'),
And in the controller instantiate the class:
$objPHPExcel = new \PHPExcel();

The problem is related to autoload PHPExcel classes. The vendor/autoload.php file it’s an auto-generated file. The implication is "don’t edit this file and expect your changes to stick".
In alternative, to avoid to have problems with autoload PHPExcel classes, is available an easy integration of PHPOffice/PHPExcel library into zend framework 2, using the zf2 module MvlabsPHPExcel.
After that you need to enable the MvlabsPHPExcel module:
<?php
return [
'modules' => [
// ...
'MvlabsPHPExcel',
],
// ...
];
And after that you be able to use inside the controller.
$phpExcelObject = $this->serviceLocator->get('mvlabs.phpexcel.service')->createPHPExcelObject();

Related

PHP - How to access Twilio in a composer namespace environment

I've been working with Rachet WebSockets and created a simple chat application. The example uses a WebSocket namespace. This is my first time using namespace. Now I'm trying to add Twilio service but can seem to add Twilio to my namespace.
I know it is autoloaded in the autoload_files.php
<?php
// autoload_files.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
$vendorDir . '/twilio/sdk/Services/Twilio.php',
);
In the composer.json file
{
"autoload": {
"psr-0": {
"Websocket": "src"
}
},
"require": {
"cboden/ratchet": "^0.3.3",
"twilio/sdk": "^4.5"
}
}
I followed the steps from this website : https://www.twilio.com/docs/libraries/php#using-without-composer
I'm calling twilio inside a method of my class like this:
$AccountSid = "xxxxxxxxxxxxxxxxx";
$AuthToken = "xxxxxxxxxxxxxxxxx";
$client = new Client($sid, $token);
$message = $client->account->messages->create(array(
'To' => "+555555555",
'From' => "+555555555",
'Body' => "This is a test",
));
Keep getting this error: Uncaught Error: Class 'Websocket\Client' not found in ......
I'm very new to composer and namespace, hope this is enough information to help me.
I had to update Twilio,
ran composer require twilio/sd
- Removing twilio/sdk (4.12.0)
- Installing twilio/sdk (5.4.1)
Downloading: 100%
Now I'm able to use Twilio\Rest\Client; since it was missing before.
When using namespaces, PHP will always start looking for classes which aren't prepended with their own namespace in the current one.
In your case the current namespace would be Websocket, thus PHP is trying to autoload the class Websocket\Client, to prevent this, you have two options :
1) Tell PHP where to look by using use :
use Twilio\Rest\Client;
2) Prepend the correct namespace
$client = new \Twilio\Rest\Client($sid, $token);

Stripe - PHP Fatal error: Class 'Stripe\Charge' not found

I've been following the Stripe documentation and I am unable to create a "charge".
Charge.php
require('/var/www/stripe-php-2.1.1/lib/Stripe.php');
\Stripe\Stripe::setApiKey("KEY_HERE");
\Stripe\Charge::create(array(
"amount" => 400,
"currency" => "usd",
"source" => "TOKEN_HERE", // obtained with Stripe.js
"description" => "Charge for test#example.com"
));
?>
I'm able to process the first command "\Stripe\Stripe::setApiKey("KEY_HERE");" but receive an error when processing the next and receive the following error:
"Class 'Stripe\Charge' not found in /var/www/charge.php"
Here is an updated answer to this question.
From Dana at Stripe:
If you prefer not to use Composer, our latest PHP bindings (>=2.x)
include a init.php file that you can add to your project. Download and
unzip the folder whereever you'd like, then include this init.php at
the top of your scripts you use to communicate with the Stripe API,
changing the path to the location of this file. Just like this:
require_once('/path/to/stripe-php/init.php')
And that's what worked for me.
If you don't use composer to install the Stripe library you will need to manually include all of the Stripe classes.
Composer is the preferred way as it will handle the autoloading of classes. Here is a sample composer file:
{
"require": {
"stripe/stripe-php": "2.*"
}
}
And then from a command line you would need to run composer update while in the directory for your project. Afterwards, just add require 'vendor/autoload.php'; to the top of your php file.
Otherwise, replace require('/var/www/stripe-php-2.1.1/lib/Stripe.php');with this code to include all of the classes:
$stripeClassesDir = __DIR__ . '/stripe-php-2.1.1/lib/';
$stripeUtilDir = $stripeClassesDir . 'Util/';
$stripeErrorDir = $stripeClassesDir . 'Error/';
set_include_path($stripeClassesDir . PATH_SEPARATOR . $stripeUtilDir . PATH_SEPARATOR . $stripeErrorDir);
function __autoload($class)
{
$parts = explode('\\', $class);
require end($parts) . '.php';
}

Reinit composer autoload

After updating via the Composer i want to initialize the application and send it events
"scripts": {
"post-update-cmd": [
"Acme\\Bundle\\DemoBundle\\Composer\\ScriptHandler::notify"
handler
public static function notify(CommandEvent $event)
{
// init app
require __DIR__.'/../../../../../../app/autoload.php';
require __DIR__.'/../../../../../../app/AppKernel.php';
$kernel = new \AppKernel('dev', true);
$kernel->boot();
// send event
$dispatcher = $kernel->getContainer()->get('event_dispatcher');
$dispatcher->dispatch('acme.installed', new Event())
}
If run the update through the composer.phar then everything works fine.
But I need to run the update from the application. I add composer to requirements and call bin\composer update.
In this case there is a conflict of autoloader. Composer connects the autoloader from the application, change it, and does not connect it again.
Need to destroy the old and create a new autoloader. I found out that the old autoloader can be accessed via $GLOBALS['loader'].
I came to this decision
public static function notify(CommandEvent $event)
{
// init loader
require __DIR__.'/../../../../../../vendor/composer/autoload_real.php';
$GLOBALS['loader']->unregister();
$GLOBALS['loader'] = require __DIR__.'/../../../../../../app/autoload.php';
// init app
require_once __DIR__.'/../../../../../../app/AppKernel.php';
// ...
But this option does not work because autoloading via file broadcast Composer in normal require and leads to connection conflict.
For example:
"name": "kriswallsmith/assetic",
"autoload": {
"files": [ "src/functions.php" ]
},
translate to
require $vendorDir . '/kriswallsmith/assetic/src/functions.php';
throw error
PHP Fatal error: Cannot redeclare assetic_init() (previously declared in /vendor/kriswallsmith/assetic/src/functions.php:20) in /vendor/kriswallsmith/assetic/src/functions.php on line 26
I create autoloader and duplicate the code of /vendor/composer/autoload_real.php and /app/autoload.php. Recommendation from Seldaek #2474
public static function notify(CommandEvent $event)
{
if (isset($GLOBALS['loader']) && $GLOBALS['loader'] instanceof ClassLoader) {
$GLOBALS['loader']->unregister();
}
$GLOBALS['loader'] = $this->getClassLoader();
require_once __DIR__.'/../../../../../../app/AppKernel.php';
$kernel = new \AppKernel('dev', true);
$kernel->boot();
// send event
$dispatcher = $kernel->getContainer()->get('event_dispatcher');
$dispatcher->dispatch('acme.installed', new Event())
}
protected function getClassLoader()
{
$loader = new ClassLoader();
$vendorDir = __DIR__.'/../../../../../../vendor';
$baseDir = dirname($vendorDir);
$map = require $vendorDir . '/composer/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$classMap = require $vendorDir . '/composer/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
$includeFiles = require $vendorDir . '/composer/autoload_files.php';
foreach ($includeFiles as $file) {
require_once $file;
}
// intl
if (!function_exists('intl_get_error_code')) {
require_once $vendorDir.'/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php';
$loader->add('', $vendorDir.'/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs');
}
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
return $loader;
}
I think I am a bit scared about what you are about to do: You want to update the components of a running application while these components are actively used. You hope that any update will run perfectly well so that after the update the application will continue to work - especially will continue to be able to do further updates.
I don't think this is a valid assumption! I have been using Composer for a while, and I have seen plenty of reasons why it did not update some parts of my dependencies, which most of the time were due to some network failure. Just think of using something from Github, and then Github is down.
What would happen then? You were probably able to download some parts, unable to download some more, and the autoloader was not updated. So the updated part now requires something new that got also downloaded, but cannot be autoloaded because some component after that failed to download. And this component is essential to repeat the update! You just broke your application, and you cannot fix it.
I can also think about very strange effects happening if the autoloader is partially loading old classes, then gets updated, and after that loads new classes that use new versions of the already loaded old classes that changed incompatible. So the assumption that you can change the components of the application during the runtime of one request seems to be very odd.
There is no way to unload a class in PHP. Once it is declared, it cannot be changed (not taking the "runkit" extension into account).
If you indeed want to get an update of your application, I think it is a better idea to duplicate everything, update the non-active copy of the application, then check if the update was successful, and after that copy it back, i.e. use symlinks to point to the current and next version and switch these.

Using FirePHP with Zend Framework 2

I'm trying to use FirePHP with Zend Framework 2, but there seems to be something missing. Here's the basic code I'm trying to run:
$writer = new Zend\Log\Writer\FirePhp();
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('FirePHP logging enabled');
The error I get is "FirePHP Class not found". I was initially puzzled because I do have a FirePhp class in my Zend/Log/Writer folder. But then I saw that the class constructor requires a FirePhp\FirePhpInterface object. So I checked the Zend/Log/Writer/FirePhp folder and there's a FirePhpBridge class in there that implements FirePhpInterface, but it also requires a FirePHP instance in the constructor. I don't have any FirePHP.php file in my Zend/Log/Writer/FirePhp folder. Am I supposed to get this from somewhere else?
Update
I now have managed to get FirePHP working, but I'm trying to figure out how to do it in a clean way so this works. The only way I've gotten it to work is putting it in the root directory of my project and doing the following:
include_once('FirePHP.php');
$writer = new Zend\Log\Writer\FirePhp(new Zend\Log\Writer\FirePhp\FirePhpBridge(FirePHP::getInstance(true)));
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info('FirePHP logging enabled');
I assume that normally I should be able to create a writer like so:
$writer = new Zend\Log\Writer\FirePhp();
However, where this goes wrong I believe is in the getFirePhp() function of the Zend\Log\Writer\FirePhp class. The class does this:
if (!$this->firephp instanceof FirePhp\FirePhpInterface
&& !class_exists('FirePHP')
) {
// No FirePHP instance, and no way to create one
throw new Exception\RuntimeException('FirePHP Class not found');
}
// Remember: class names in strings are absolute; thus the class_exists
// here references the canonical name for the FirePHP class
if (!$this->firephp instanceof FirePhp\FirePhpInterface
&& class_exists('FirePHP')
) {
// FirePHPService is an alias for FirePHP; otherwise the class
// names would clash in this file on this line.
$this->setFirePhp(new FirePhp\FirePhpBridge(new FirePHPService()));
}
This is where I get lost as to how I'm supposed to set things up so that this class_exists('FirePHP') call finds the right class and new FirePHPService() also works properly.
First you should add this code to Module.php of your module
return array(
//...
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
);
and here content of autoload_classmap.php
<?php
return array(
'FirePHP' => realpath(APPLICATION_PATH . '/vendor/FirePHP').'/FirePHP.php',
);
FirePHP.php(renamed from FirePHP.class.php) downloaded from official site.
then you can write below code in any place of your module and it will work
use Zend\Log\Writer\FirePhp;
use Zend\Log\Logger;
$writer = new FirePhp();
$logger = new Logger();
$logger->addWriter($writer);
$logger->info("hi");
Am I supposed to get this from somewhere else?
Yes, you need to get FirePHP into your project and autoloading.
If you're using composer (and I recommend that you do), just add:
"firephp/firephp-core" : "dev-master"
(or similar) in your composer.json and update. If you're not using composer, you should grab the firephp libs, and let your autoloader know about them.

How to install the AWS SDK in Yii

I would like to use the Amazon AWS SDK for PHP in my Yii project, however I get all kinds of include errors (such as include(CFCredentials.php): failed to open stream: No such file or directory ).
I think it may be related to Yii's assumption that class names must match file names...
What can we do??
I've made that:
spl_autoload_unregister(array('YiiBase', 'autoload'));
require_once PATH_TO_AWS_SDK . 'sdk.class.php';
// I write down in PATH_TO_AWS_SDK.'config.inc.php' my CFCredentials
spl_autoload_register(array('YiiBase', 'autoload'));
$amazon_opts = array(
'curlopts' => array(
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_FORBID_REUSE => false,
),
);
$amazon = new AmazonSES();
$response = $amazon->get_send_quota($amazon_opts);
This worked beautifully:
// Include the SDK
Yii::import('application.vendors.aws.*');
spl_autoload_unregister(array('YiiBase', 'autoload'));
require_once 'sdk.class.php';
spl_autoload_register(array('YiiBase', 'autoload'));
// Instantiate the AmazonEC2 class
$ec2 = new AmazonEC2();
In case someone stumbles upon this issue, I've found that if one is using the PHAR file directly (poor decision, I know) and importing via require_once, you cannot call spl_autoload_register to re-add YiiBase autoload until after your SDK call is complete.
At least this was our case when using the StsClient to call assume role with an IAM role.
This is more easier way, You can use Yii S3 Upload extension.
http://www.yiiframework.com/extension/s3upload/

Categories