image resize zf2 - zend-framework2

I need to implement image resize functionality (preferably with gd2 library extension) in zend framework 2.
I could not find any component/helper for the same. Any references?
If i want to create one, where should I add it. In older Zend framework, there was a concept of Action Helper, what about Zend framework 2 ?
Please suggest the best solution here.

I currently use Imagine together with Zend Framework 2 to handle this.
Install Imagine: php composer.phar require imagine/Imagine:0.3.*
Create a service factory for the Imagine service (in YourModule::getServiceConfig):
return array(
'invokables' => array(
// defining it as invokable here, any factory will do too
'my_image_service' => 'Imagine\Gd\Imagine',
),
);
Use it in your logic (hereby a small example with a controller):
public function imageAction()
{
$file = $this->params('file'); // #todo: apply STRICT validation!
$width = $this->params('width', 30); // #todo: apply validation!
$height = $this->params('height', 30); // #todo: apply validation!
$imagine = $this->getServiceLocator()->get('my_image_service');
$image = $imagine->open($file);
$transformation = new \Imagine\Filter\Transformation();
$transformation->thumbnail(new \Imagine\Image\Box($width, $height));
$transformation->apply($image);
$response = $this->getResponse();
$response->setContent($image->get('png'));
$response
->getHeaders()
->addHeaderLine('Content-Transfer-Encoding', 'binary')
->addHeaderLine('Content-Type', 'image/png')
->addHeaderLine('Content-Length', mb_strlen($imageContent));
return $response;
}
This is obviously the "quick and dirty" way, since you should do following (optional but good practice for re-usability):
probably handle image transformations in a service
retrieve images from a service
use an input filter to validate files and parameters
cache output (see http://zend-framework-community.634137.n4.nabble.com/How-to-handle-404-with-action-controller-td4659101.html eventually)
Related: Zend Framework - Returning Image/File using Controller

Use a service for this and inject it to controllers needing the functionality.

Here is a module called WebinoImageThumb in Zend Framework 2. Checkout this. It has some great feature such as -
Image Resize
Image crop, pad, rotate, show and save images
Create image reflection

For those who are unable to integrate Imagine properly like me..
I found another solution WebinoImageThumb here which worked perfectly fine with me. Here is little explanation if you don't want to read full documentation :
Run: php composer.phar require webino/webino-image-thumb:dev-develop
and add WebinoImageThumb as active module in config/application.config.php which further looks like :
<?php
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'WebinoImageThumb'
),
.. below remains the same
Now in your controller action use this through service locator like below :
// at top on your controller
use Zend\Validator\File\Size;
use Zend\Validator\File\ImageSize;
use Zend\Validator\File\IsImage;
use Zend\Http\Request
// in action
$file = $request->getFiles();
$fileAdapter = new \Zend\File\Transfer\Adapter\Http();
$imageValidator = new IsImage();
if ($imageValidator->isValid($file['file_url']['tmp_name'])) {
$fileParts = explode('.', $file['file_url']['name']);
$filter = new \Zend\Filter\File\Rename(array(
"target" => "file/path/to/image." . $fileParts[1],
"randomize" => true,
));
try {
$filePath = $filter->filter($file['file_url'])['tmp_name'];
$thumbnailer = $this->getServiceLocator()
->get('WebinoImageThumb');
$thumb = $thumbnailer->create($filePath, $options = [], $plugins = []);
$thumb->adaptiveResize(540, 340)->save($filePath);
} catch (\Exception $e) {
return new ViewModel(array('form' => $form,
'file_errors' => array($e->getMessage())));
}
} else {
return new ViewModel(array('form' => $form,
'file_errors' => $imageValidator->getMessages()));
}
Good luck..!!

In order to resize uploaded image on the fly you should do this:
public function imageAction()
{
// ...
$imagine = $this->getImagineService();
$size = new \Imagine\Image\Box(150, 150);
$mode = \Imagine\Image\ImageInterface::THUMBNAIL_INSET;
$image = $imagine->open($destinationPath);
$image->thumbnail($size, $mode)->save($destinationPath);
// ...
}
public function getImagineService()
{
if ($this->imagineService === null)
{
$this->imagineService = $this->getServiceLocator()->get('my_image_service');
}
return $this->imagineService;
}

Related

Request GetHumanStatus{model: ArrayObject} is not supported: ZF2

Creating a model for Sofort integration and extend the payments object from the payum module to use it in the capture.
<?php
namespace Reisesparer\Model;
use Payum\Core\Model\Payment;
class SofortueberWeisung extends Payment
{
protected $id;
}
Controller method for the sofort is like follows: I have created a seperate Model where extend to the payments object
public function sofortAction()
{
$storage = $this->getServiceLocator()->get('payum')->getStorage('Reisesparer\Model\SofortueberWeisung');
$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode('EUR');
$payment->setTotalAmount(123); // 1.23 EUR
$payment->setDescription('A description');
$payment->setClientId('anId');
$payment->setClientEmail('foo#example.com');
$storage->update($payment);
$captureToken = $this->getServiceLocator()->get('payum.security.token_factory')->createCaptureToken(
'sofort', $payment, 'payment_done'
);
// print_r($captureToken);
// exit();
$this->redirect()->toUrl($captureToken->getTargetUrl());
}
And My config file has follows code to configure the payum/sofort mehthod in my project.
'sofort' => $sofortFactory->create(array(
'factory' => 'sofort',
'config_key' => '12345:123456:edc788a4316ce7e2ac0ede037aa623d7',
)),
And at the last my done action to capture the useful information after the successful payment is like follows:
public function doneAction()
{
$token = $this->getServiceLocator()->get('payum.security.http_request_verifier')->verify($this);
$gateway = $this->getServiceLocator()->get('payum')->getgateway($token->getgatewayName());
$gateway->execute($status = new GetHumanStatus($token));
$payment = $status->getFirstModel();
$viewModel = new ViewModel(array('status' => $status->getValue(),'details'=>$payment));
$viewModel->setTemplate('layout/pay_done');
return $viewModel;
}
Storage Config:
'storages' => array(
$detailsClass => new FilesystemStorage(__DIR__.'/../../data', $detailsClass, 'id'),
$paymentClass => new FilesystemStorage(__DIR__.'/../../data', $paymentClass, 'id'),
)
Now when ever i proceed with the sofort payment method to capture the payment it gaves me the error and not proceed further. but the other method like paypal, stripe and authorized.net are working fine in the same project how to resolve this issues
Error:
Request GetHumanStatus{model: ArrayObject} is not supported.

Phalcon PHP post link with JavaScript confirmation dialog

I am developing a CRUD system in Phalcon PHP (version 1.3.4).
My goal is to create a link (delete row), that asks for confirmation on click (JavaScript confirmation box) and then goes (request type POST) to the link.
So lets say a user clicks on the "delete row" button.
JavaScript confirmation "Are you sure you want to delete this row?"
User clicks "yes"
Webpage does a POST to "/users/delete/1"
I know CakePHP has a function (FormHelper::postLink()) that does exactly that.
I was wondering if Phalcon PHP also had a function like this.
I see three possibilities to achieve what you want. One is to create a macro in Volt template, second is to add a function to your View. Third and closest to - what I understand is your wish - is to extend Phalcons tag helper and this is part I will describe here.
Phalcon has its own Tag helper to allow you to easily create some elements. postLink is not a part that is implemented there, but you can easily achieve it. In my example I have namespace of Application with class of Tag that extends from \Phalcon\Tag. This is my base for this tutorial.
// Tag.php
namespace Application;
class Tag extends \Phalcon\Tag
{
static public function postLink() {
return '<strong>TEST TAG</strong>';
}
}
To force Phalcon DI to use this class, it is necessary to override it's standard declaration from engine by declaring it by hand as a new DI service:
// services.php
$di['tag'] = function() {
return new \Application\Tag();
};
You can test if it is working properly by typing {{ tag.postLink() }} in Volt template or with $this->tag->postLink() if using phtml template.
Now you can fill your Tag::postLink() method with HTML and parameters you wish it will produce:
namespace Application;
class Tag extends \Phalcon\Tag
{
static $forms = [];
static public function postLink($title, $url, $options = array()) {
// random & unique form ID
while ($randId = 'f_' . mt_rand(9000, 999999)) {
if (!isset(self::$forms[$randId])) {
self::$forms[$randId] = true;
break;
}
}
// dialog message
$dialogMessage = isset($options['message']) && $options['message'] ? $options['message'] : 'Are you sure you want to go on?';
$html = <<<HTML
<form action="{$url}" method="post" id="{$randId}">
<!-- maybe not necessary part -->
<input type="hidden" name="confirmed" value="1" />
</form>
{$title}
HTML;
return $html;
}
}
Now you can run it like this:
{{ tag.postLink('delete', '/users/delete/1') }}
{% set formOptions = ['message' : 'Are you sure you want to delete user Kialia Kuliambro?'] %}
{{ tag.postLink('delete', '/users/delete/1', formOptions) }}
{{ tag.postLink('delete', '/users/delete/1', ['message' : 'Are you sure you want to delete user Kialia Kuliambro?']) }}
Have fun extending :)
There's a few ways to implement such behavior in phalcon. Before anything, we need to understand how views and view helpers work in phalcon. And if you pay close attention, you'll notice, both .volt and .phtml have direct access to the DI.
In volt, for example, you can access the flash service, and output its messages by calling:
{{ flash.output() }}
which gets converted to the phtml: <?php echo $this->flash->output(); ?>
Thus my solution focuses on defining a new service in the DI which volt can access. In CakePHP, the syntax for postLink(), looks something like: echo $this->Form->postLink() while the function is actually defined in a class named FormHelper. So my solution will do the same thing, define a class FormHelper, then inject it into the view under the name Form.
Create an app/helpers/ directory.
Update your app/config/config.php file adding a reference to our new directory: 'helpersDir'=> APP_PATH . '/app/helpers/'
Update your app/config/loader.php file adding $config->application->helpersDir to the registered directories.
Create a new file app/helpers/FormHelper.php
Copy-paste the following code into the file:
<?php
use Phalcon\Tag;
class FormHelper extends Tag
{
protected $_lastAction = '';
public function dottedNameToBracketNotation($name)
{
$parts=explode('.',$name);
$first = array_shift($parts);
$name=$first . ($parts ? '[' . implode('][', $parts) . ']' : '');
return $name;
}
protected function flatten(array $data, $separator = '.')
{
$result = [];
$stack = [];
$path = null;
reset($data);
while (!empty($data)) {
$key = key($data);
$element = $data[$key];
unset($data[$key]);
if (is_array($element) && !empty($element)) {
if (!empty($data)) {
$stack[] = [$data, $path];
}
$data = $element;
reset($data);
$path .= $key . $separator;
} else {
$result[$path . $key] = $element;
}
if (empty($data) && !empty($stack)) {
list($data, $path) = array_pop($stack);
reset($data);
}
}
return $result;
}
protected function _confirm($message, $okCode, $cancelCode = '', $options = [])
{
$message = json_encode($message);
$confirm = "if (confirm({$message})) { {$okCode} } {$cancelCode}";
if (isset($options['escape']) && $options['escape'] === false) {
$confirm = $this->h($confirm);
}
return $confirm;
}
public function h($text, $double = true, $charset = 'UTF-8')
{
return htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, $charset, $double);
}
protected function _lastAction($url)
{
$action = $url;//Router::url($url, true);
$query = parse_url($action, PHP_URL_QUERY);
$query = $query ? '?' . $query : '';
$this->_lastAction = parse_url($action, PHP_URL_PATH) . $query;
}
public function postLink($title, $url = null, array $options = [])
{
$out='';
$options += ['block' => null, 'confirm' => null];
$requestMethod = 'POST';
if (!empty($options['method'])) {
$requestMethod = strtoupper($options['method']);
unset($options['method']);
}
$confirmMessage = $options['confirm'];
unset($options['confirm']);
$formName = str_replace('.', '', uniqid('post_', true));
$formOptions = [
'name' => $formName,
'style' => 'display:none;',
'method' => 'post',
];
if (isset($options['target'])) {
$formOptions['target'] = $options['target'];
unset($options['target']);
}
$formOptions[0]=$url;
$out.=$this->form($formOptions);
$out .= $this->hiddenField(['_method','value' => $requestMethod]);
$fields = [];
if (isset($options['data']) && is_array($options['data'])) {
foreach ($this->flatten($options['data']) as $key => $value) {
$out .= $this->hiddenField([$this->dottedNameToBracketNotation($key),'value' => $value]);
}
unset($options['data']);
}
$out .= $this->endForm();
//This is currently unsupported
if ($options['block']) {
if ($options['block'] === true) {
$options['block'] = __FUNCTION__;
}
//$this->_View->append($options['block'], $out);
$out = '';
}
unset($options['block']);
$url = '#';
$onClick = 'document.' . $formName . '.submit();';
if ($confirmMessage) {
$options['onclick'] = $this->_confirm($confirmMessage, $onClick, '', $options);
} else {
$options['onclick'] = $onClick . ' ';
}
$options['onclick'] .= 'event.returnValue = false; return false;';
$options[0]=$url;
$options[1]=$title;
$options[2]=false;
$out .= $this->linkTo($options);
return $out;
}
}
Edit your app/config/services.php file and add in:
$di->set('Form',function () {
return new FormHelper();
});
(you could make "Form" lowercase if you want, both work. I made it capital to closer resemble CakePHP's syntax. Do note that Volt is case sensitive when trying to access services but phtml will lowercase it.)
Edit the template you want to test the code on, such as app/views/index/test.volt
Copy-paste the following code into there:
{{ Form.postLink(' Delete','',['confirm':'Are you sure you want to delete #4?','data':['a':['b','c']]]) }}
Alternatively for phtml, use: <?php echo $this->form->postLink(' Delete', '', array('confirm' => 'Are you sure you want to delete #4?', 'data' => array('a' => array('b', 'c')))); ?>
Run it, and watch it work its magic, just render your index/test.volt template by visiting /index/test in your address bar. (Make sure you defined such an action in your index controller)
In terms, of other solutions, you could also use $compiler->addFunction() to make functions available to volt, one at time. The page in the manual gives the example of $compiler->addFunction('shuffle', 'str_shuffle');. You can attempt to override the factoryDefault for "tag" in the DI, and use the helper we already defined which extends tag. So you'd just change it from "form" to "tag" like so: $di->set('tag',function () {return new FormHelper();}); but, as you can see, it won't make the function postLink() available to volt as a function, you'll notice you still need to access it as tag.postLink(). Rather, all the \Phalcon\Tag functions are actually hard-coded into the volt engine. You can see this clearly by viewing the zephir source code of the \Phalcon\Mvc\View\Engine\Volt\Compiler class available over here. For your convenience, and in case the link ever gets broken, I have posted a snippet here which shows the "tag" functions in volt are actually hard-coded into it:
if method_exists(className, method) {
let arrayHelpers = this->_arrayHelpers;
if typeof arrayHelpers != "array" {
let arrayHelpers = [
"link_to": true,
"image": true,
"form": true,
"select": true,
"select_static": true,
"submit_button": true,
"radio_field": true,
"check_field": true,
"file_field": true,
"hidden_field": true,
"password_field": true,
"text_area": true,
"text_field": true,
"email_field": true,
"date_field": true,
"tel_field": true,
"numeric_field": true,
"image_input": true
];
let this->_arrayHelpers = arrayHelpers;
}
if isset arrayHelpers[name] {
return "$this->tag->" . method . "(array(" . arguments . "))";
}
return "$this->tag->" . method . "(" . arguments . ")";
}
So, if you'd like to "hack" in a few more methods by extending the \Phalcon\Tags class, you're out of luck. However, as demonstrated on the volt documentation page, there exists the concept of registering custom extensions to work with volt. The documentation gives the example of: $compiler->addExtension(new PhpFunctionExtension());
Where the source of the class is:
<?php
class PhpFunctionExtension
{
/**
* This method is called on any attempt to compile a function call
*/
public function compileFunction($name, $arguments)
{
if (function_exists($name)) {
return $name . '('. $arguments . ')';
}
}
}
This would allow volt access to any function you'd like, without having to manually register every possible function you could possibly ever need. You can test this by trying to access str_shuffle in volt, like we did before with $compiler->addFunction('shuffle', 'str_shuffle'); but this time without having to register it.
In terms of other solutions, you could also try to integrate CakePHP and PhalconPHP together, and attempt to call CakePHP's view helpers from PhalconPHP, but then you'd run into a problem of CakePHP not understanding your router setup you have configured in Phalcon. But, if you're determined, you could code all the routes and config for CakePHP and run it alongside PhalconPHP, but I'd highly discourage such a desperate workaround. And, finally, if you understand how the function works, and you barely use it, you could get away with just hard-coding the HTML in the first place. Honestly, CakePHP's logic doesn't look so sound to me in the first place because it has to corrupt your HTML document with a form inserted which can bother your layout. I think it would make more sense to generate a form dynamically with JavaScript, if we're using JavaScript already, and append it to the <body> when the button is clicked, then submit the form we just created dynamically. But, you wanted a CakePHP implementation, so I coded it as close to the logic they used as possible. It's not perfect, in terms of supporting all their features, such as block, but it should suit most of your needs.
I can always revise my implementation, but I think it demonstrates how to work with Phalcon pretty well for those migrating from CakePHP.

Can't get Task to Send Email in Symfony 1.4

I created a task to automate emailing a report in Symfony 1.4. Both this task and a related module for viewing in the web share a custom PHP class file. The task is able to pull in the data correctly, but I have not been able to get it to send out the email. I attempted to follow the official Symfony 1.4 documentation as well as a number of examples from a Google search, but none are solving my problem. The terminal isn't displaying any error either.
My Code:
<?php
require_once sfConfig::get('sf_lib_dir').'/vendor/sesame/reports/reports.class.php';
//use reports;
class reportsTask extends sfBaseTask
{
protected function configure()
{
// // add your own arguments here
// $this->addArguments(array(
// new sfCommandArgument('my_arg', sfCommandArgument::REQUIRED, 'My argument'),
// ));
$this->addOptions(array(
new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name'),
new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'),
new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'The connection name', 'doctrine'),
new sfCommandOption('type', null, sfCommandOption::PARAMETER_OPTIONAL, 'The output type of the report', 'email')
// add your own options here
));
$this->namespace = '';
$this->name = 'reports';
$this->briefDescription = '';
$this->detailedDescription = <<<EOF
The [reports|INFO] task does things.
Call it with:
[php symfony reports|INFO]
EOF;
}
protected function execute($arguments = array(), $options = array())
{
$databaseManager = new sfDatabaseManager($this->configuration);
$databaseManager->loadConfiguration();
$reports = new reports();
$output = $reports->buildReport($options['type']);
switch($options['type']){
case 'csv':
echo $output;
break;
case 'email':
$message = $this->getMailer()->compose($output['from'], $output['to'], $output['subject']);
$message->setBody($output['body']['content'], $output['body']['type']);
$message->attach(Swift_Attachment::newInstance($output['attachment']['content'], $output['attachment']['name'], $output['attachment']['type']));
$this->getMailer()->sendNextImmediately()->send($message) or die('email failed to deliver');
$output = array('status'=>'success', 'to'=>$output['to']);
default:
$this->logSection('results', json_encode($output));
}
}
}
The terminal command being attempted from the project root:
php symfony reports
Any answers leading to the right path would be most helpful. Please keep in mind that I need to stay with version 1.4. The server is capable of sending off emails and my module version does just that when invoked by a URL. I need it to run on the command line though so I can set up a cron.

cakephp2 i want to only tweet

I use cakephp2.x and use this Consuming OAuth-enabled APIs with CakePHP http://code.42dh.com/oauth/
I only want to be able to tweet. But I can't now.
Download consuming package and put app/vender/OAuth
Write this code in PostsController
App::import('Vendor', 'OAuth/OAuthClient');
public function add() {
$client = $this->createClient();
$requestToken = $client->getRequestToken('https://api.twitter.com/oauth/request_token',
'http://' . $_SERVER['HTTP_HOST'] . '/lolch/posts');
if ($requestToken) {
$this->Session->write('twitter_request_token', $requestToken);
$this->redirect('https://api.twitter.com/oauth/authorize?oauth_token='
. $requestToken->key);
}
}
public function callback() {
$requestToken = $this->Session->read('twitter_request_token');
$client = $this->createClient();
$accessToken = $client->getAccessToken('https://api.twitter.com/oauth/access_token',
$requestToken);
$client->post($accessToken->key, $accessToken->secret, 'https://api.twitter.com/1.1/statuses/update.json', array('status' =>
'hello world!'));
private function createClient() {
return new OAuthClient('my key', 'my secret');
}
Where should I change the code??
You can use https://github.com/LubosRemplik/CakePHP-Twitter-API-Plugin‎ plugin or other twitter plugin for cakephp and read the documentation there to apply what you want. It is easy to use ready made plugin than reinventing the wheel.

Zend 2 Auth with Bcrypt?

Google doesn't have much of a solution (similar question but no answer).
Because bcrypt generates a new hash each time, the authentication fails. I've looked into the code (perhaps extend class myself) but it's pretty messy (would prefer a native solution). How can I use the $bcrpt->verify() with $identity->isValid()?
Edit: For now, I've subclassed the authentication DbTable class, and it's working, but I highly doubt it's optimized/"fully right". Still looking for an "elegant" solution.
You can use:
Zend\Authentication\Adapter\DbTable\CallbackCheckAdapter
Like this :
use Zend\Authentication\Adapter\DbTable\CallbackCheckAdapter as AuthAdapter;
use Zend\Crypt\Password\Bcrypt;
$credentialValidationCallback = function($dbCredential, $requestCredential) {
return (new Bcrypt())->verify($requestCredential, $dbCredential);
};
$authAdapter = new AuthAdapter($dbAdapter, 'user', 'login', 'password', $credentialValidationCallback);
// ...
As you should know, BCrypt hashes using a salt. And that salt is generated again randomly each time. That drastically increases the hardness of finding all passwords if your database is compromised. Thus, indeed, it will generate a new hash each time.
My own solution for the problem that you were having, is having my own Zend\Authentication adapter, that would retrieve a user model from the database (using the username/email), and then calling $user->checkPassword($credential);. That method would get an instance of Zend\Crypt\Password\Bcrypt. Which would simply call $bcrypt->verify() on the given password, and the hash in the user model.
I've done it like this (test code and it works)..;
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$bcrypt = new Bcrypt();
$user = new User();
$user->exchangeArray($form->getData());
$password = $user->password;
$data = $this->getUserTable()->selectUser($user->username);
if (!$data)
{
echo 'user not found';
} else {
if ($bcrypt->verify($password, $data->hash)) {
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$authAdapter = new AuthAdapter(
$dbAdapter,
'cms_users',
'username',
'hash'
);
$authAdapter->setIdentity($user->username)
->setCredential($data->hash);
$result = $auth->authenticate($authAdapter);
echo $result->getIdentity() . "\n\n";
// do you thing on succes/failure
} else {
echo 'invalid password';
}
}
}
}

Resources