Is there a way when uploading images (JPEG) to check the DPI?
I would like to integrate it into a form, so as a validator.
You have to open the image with Imagick (or Gmagick) and then call getImageResolution.
$image = new Imagick($path_to_image);
var_dump($image->getImageResolution());
result:
Array
(
[x]=>75
[y]=>75
)
Edit:
For an integration into symfony, you can use a custom validator for that. You extends the default one to validate a file and add the DPI restriction.
Create this one into /lib/validator/myCustomValidatorFile .class.php:
<?php
class myCustomValidatorFile extends sfValidatorFile
{
protected function configure($options = array(), $messages = array())
{
parent::configure($options, $messages);
$this->addOption('resolution_dpi');
$this->addMessage('resolution_dpi', 'DPI resolution is wrong, you should use image with %resolution_dpi% DPI.');
}
protected function doClean($value)
{
$validated_file = parent::doClean($value);
$image = new Imagick($validated_file->getTempName());
$resolution = $image->getImageResolution();
if (empty($resolution))
{
throw new sfValidatorError($this, 'invalid');
}
if ((isset($resolution['x']) && $resolution['x'] < $this->getOption('resolution_dpi')) || (isset($resolution['y']) && $resolution['y'] < $this->getOption('resolution_dpi')))
{
throw new sfValidatorError($this, 'resolution_dpi', array('resolution_dpi' => $this->getOption('resolution_dpi')));
}
return $validated_file;
}
}
Then, inside your form, use this validator for your file:
$this->validatorSchema['file'] = new myCustomValidatorFile(array(
'resolution_dpi' => 300,
'mime_types' => 'web_images',
'path' => sfConfig::get('sf_upload_dir'),
'required' => true
));
Related
I'm trying to upload an image in Sales Rules in Magento,
I follow this tutorial :
https://wiki.magento.com/display/m1wiki/How+to+create+an+image+or+video+uploader+for+the+Magento+Admin+Panel
My fields must be in native SalesRules Magento module , so I made overloading following files:
Mage_Adminhtml_Block_Promo_Quote_Edit_Form
protected function _prepareForm()
{
$form = new Varien_Data_Form(array('id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post','enctype' => 'multipart/form-data'));
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
Mage_Adminhtml_Block_Promo_Quote_Edit_Tab_Main
I add my field in _prepareForm() function
$fieldset->addField('image_promo', 'image', array(
'label' => Mage::helper('salesrule')->__('Image'),
'required' => false,
'name' => 'image_promo',
));
and in this file, I change my return:
From
return parent::_prepareForm();
To
return Mage_Adminhtml_Block_Widget_Form::_prepareForm();
And finally I'm overloading this file :
Mage_Adminhtml_Promo_QuoteController and I'm adding to saveAction() function :
if(isset($_FILES['image_promo']['name']) and (file_exists($_FILES['image_promo']['tmp_name']))) {
try {
$uploader = new Varien_File_Uploader('image_promo');
$uploader->setAllowedExtensions(array('jpg','jpeg','gif','png')); // or pdf or anything
$uploader->setAllowRenameFiles(false);
// setAllowRenameFiles(true) -> move your file in a folder the magento way
// setAllowRenameFiles(true) -> move your file directly in the $path folder
$uploader->setFilesDispersion(false);
$path = Mage::getBaseDir('media') . DS ;
$uploader->save($path, $_FILES['image_promo']['name']);
$data['image_promo'] = $_FILES['image_promo']['name'];
}catch(Exception $e) {
Mage::logException($e);
}
}else {
if(isset($data['image_promo']['delete']) && $data['image_promo']['delete'] == 1)
$data['image_main'] = '';
else
unset($data['image_promo']);
}
When I try to save without upload any files, magento work properly, but when i have an image, i not pass through my saveAction, and i'm being redirected on Dashboard ...
I'm trying to had an hidden form_key by this way in my Main.php (Second file)
$fieldset->addField('form_key', 'hidden', array(
'value' => Mage::getSingleton('core/session')->getFormKey(),
'name' => 'form_key',
));
But this doesn't change anything !
Any idea ?
I am trying to create an admin module in Magento.
Step 1:
which contains the following fields
Step 2 : Filled some values and a Image
Step 3 : When i am trying to Save this Item, the item is saved Successfully but image is not showing here. But actually that images is copied in my Magento Media folder.
Step 4 : After the item saved successfully it is showing like this
But Actually i want it to show something like this
Here is My Code Please Find it.
_prepareForm() - fieldset code :
$fieldset->addField('image', 'file', array(
'label' => Mage::helper('modulename')->__('Image'),
'name' => 'image',
'note' => '(*.jpg, *.png, *.gif)',
));
_prepareForm() :
<?php
class Namespace_ModuleName_Block_Adminhtml_Measurement_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))),
'method' => 'post',
'enctype' => 'multipart/form-data'
)
);
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
?>
saveAction() :
public function saveAction() {
if ($data = $this->getRequest()->getPost()) {
$model = Mage::getModel('modulename/modulename');
$model->setData($data)->setId($this->getRequest()->getParam('id'));
try {
if ($model->getCreatedTime == NULL || $model->getUpdateTime() == NULL) {
$model->setCreatedTime(now())
->setUpdateTime(now());
} else {
$model->setUpdateTime(now());
}
$model->save();
if(isset($_FILES['image']['name']) and (file_exists($_FILES['image']['tmp_name']))) {
try {
$uploader = new Varien_File_Uploader('image');
$uploader->setAllowedExtensions(array('jpg','jpeg','gif','png')); // or pdf or anything
$uploader->setAllowRenameFiles(false);
// setAllowRenameFiles(true) -> move your file in a folder the magento way
// setAllowRenameFiles(true) -> move your file directly in the $path folder
$uploader->setFilesDispersion(false);
$path = Mage::getBaseDir('media') . '/modulename_images/' ;
$uploader->save($path, $model->getId().'.jpg');
$model->setImage($model->getId().'.jpg');
$model->save();
}catch(Exception $e) {
print_r($e);
die;
}
}
else {
if(isset($data['image']['delete']) && $data['image']['delete'] == 1)
$data['image_main'] = '';
else
unset($data['image']);
}
// Mage::getModel('modulename/flatrates')->saveMultipleFlatrates($data, $model->getId(),$this->getRequest()->getParam('cat_id'));
Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('modulename')->__('Item was successfully saved'));
Mage::getSingleton('adminhtml/session')->setFormData(false);
if ($this->getRequest()->getParam('back')) {
$this->_redirect('*/*/edit', array('id' => $model->getId()));
return;
}
$this->_redirect('*/*/');
return;
} catch (Exception $e) {
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
Mage::getSingleton('adminhtml/session')->setFormData($data);
$this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id')));
return;
}
}
Mage::getSingleton('adminhtml/session')->addError(Mage::helper('modulename')->__('Unable to find item to save'));
$this->_redirect('*/*/');
}
Anything wrong i did here ?
any ideas ?
If any spell mistakes i am really sorry.
In order to get the image preview, you have to use the image field type, not file, like this (look at second parameter):
$fieldset->addField('image', 'image', array(
'label' => Mage::helper('modulename')->__('Image'),
'name' => 'image',
'note' => '(*.jpg, *.png, *.gif)',
));
This is because of you have store your image in Subdirectory of media folder so you have to setvalue() of your image field before display..
like in EditAction() add this code here is my field name profile_pic
if($model->getProfilePic())
{
$model->setProfilePic('testimonial/'.$model->getProfilePic());
}
OR you can use helper to preview that image
I want to upload images in my cakephp 3.0 app. But I get the error message:
Notice (8): Undefined index: Images [APP/Controller/ImagesController.php, line 55]
Are there already some examples for uploading files (multiple files at once) in cakePHP 3.0? Because I can only find examples for cakePHP 2.x !
I think I need to add a custom validation method in my ImagesTable.php? But I can't get it to work.
ImagesTable
public function initialize(array $config) {
$validator
->requirePresence('image_path', 'create')
->notEmpty('image_path')
->add('processImageUpload', 'custom', [
'rule' => 'processImageUpload'
])
}
public function processImageUpload($check = array()) {
if(!is_uploaded_file($check['image_path']['tmp_name'])){
return FALSE;
}
if (!move_uploaded_file($check['image_path']['tmp_name'], WWW_ROOT . 'img' . DS . 'images' . DS . $check['image_path']['name'])){
return FALSE;
}
$this->data[$this->alias]['image_path'] = 'images' . DS . $check['image_path']['name'];
return TRUE;
}
ImagesController
public function add()
{
$image = $this->Images->newEntity();
if ($this->request->is('post')) {
$image = $this->Images->patchEntity($image, $this->request->data);
$data = $this->request->data['Images'];
//var_dump($this->request->data);
if(!$data['image_path']['name']){
unset($data['image_path']);
}
// var_dump($this->request->data);
if ($this->Images->save($image)) {
$this->Flash->success('The image has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The image could not be saved. Please, try again.');
}
}
$images = $this->Images->Images->find('list', ['limit' => 200]);
$projects = $this->Images->Projects->find('list', ['limit' => 200]);
$this->set(compact('image', 'images', 'projects'));
$this->set('_serialize', ['image']);
}
Image add.ctp
<?php
echo $this->Form->input('image_path', [
'label' => 'Image',
'type' => 'file'
]
);
?>
Image Entity
protected $_accessible = [
'image_path' => true,
];
In your view file, add like this, in my case Users/dashboard.ctp
<div class="ChImg">
<?php
echo $this->Form->create($particularRecord, ['enctype' => 'multipart/form-data']);
echo $this->Form->input('upload', ['type' => 'file']);
echo $this->Form->button('Update Details', ['class' => 'btn btn-lg btn-success1 btn-block padding-t-b-15']);
echo $this->Form->end();
?>
</div>
In your controller add like this, In my case UsersController
if (!empty($this->request->data)) {
if (!empty($this->request->data['upload']['name'])) {
$file = $this->request->data['upload']; //put the data into a var for easy use
$ext = substr(strtolower(strrchr($file['name'], '.')), 1); //get the extension
$arr_ext = array('jpg', 'jpeg', 'gif'); //set allowed extensions
$setNewFileName = time() . "_" . rand(000000, 999999);
//only process if the extension is valid
if (in_array($ext, $arr_ext)) {
//do the actual uploading of the file. First arg is the tmp name, second arg is
//where we are putting it
move_uploaded_file($file['tmp_name'], WWW_ROOT . '/upload/avatar/' . $setNewFileName . '.' . $ext);
//prepare the filename for database entry
$imageFileName = $setNewFileName . '.' . $ext;
}
}
$getFormvalue = $this->Users->patchEntity($particularRecord, $this->request->data);
if (!empty($this->request->data['upload']['name'])) {
$getFormvalue->avatar = $imageFileName;
}
if ($this->Users->save($getFormvalue)) {
$this->Flash->success('Your profile has been sucessfully updated.');
return $this->redirect(['controller' => 'Users', 'action' => 'dashboard']);
} else {
$this->Flash->error('Records not be saved. Please, try again.');
}
}
Before using this, create a folder in webroot named upload/avatar.
Note: The input('Name Here'), is used in
$this->request->data['upload']['name']
you can print it if you want to see the array result.
Its works like a charm in CakePHP 3.x
Now that everyone makes advertisement for his plugins here, let me do this as well. I've checked the Uploadable behavior linked in the other question, it's pretty simple and half done it seems.
If you want a complete solution that is made to scale on enterprise level check FileStorage out. It has some features I haven't seen in any other implementations yet like taking care of ensuring your won't run into file system limitations in the case you get really many files. It works together with Imagine to process the images. You can use each alone or in combination, this follows SoC.
It is completely event based, you can change everything by implementing your own event listeners. It will require some intermediate level of experience with CakePHP.
There is a quick start guide to see how easy it is to implement it. The following code is taken from it, it's a complete example, please see the quick start guide, it's more detailed.
class Products extends Table {
public function initialize() {
parent::initialize();
$this->hasMany('Images', [
'className' => 'ProductImages',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductImage'
]
]);
$this->hasMany('Documents', [
'className' => 'FileStorage.FileStorage',
'foreignKey' => 'foreign_key',
'conditions' => [
'Documents.model' => 'ProductDocument'
]
]);
}
}
class ProductsController extends ApController {
// Upload an image
public function upload($productId = null) {
if (!$this->request->is('get')) {
if ($this->Products->Images->upload($productId, $this->request->data)) {
$this->Session->set(__('Upload successful!');
}
}
}
}
class ProductImagesTable extends ImageStorageTable {
public function uploadImage($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductImage',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
public function uploadDocument($productId, $data) {
$data['adapter'] = 'Local';
$data['model'] = 'ProductDocument',
$data['foreign_key'] = $productId;
$entity = $this->newEntity($data);
return $this->save($data);
}
}
Maybe the following would help. It's a behavior who helps you to upload files very easy!
http://cakemanager.org/docs/utils/1.0/behaviors/uploadable/
Let me know if you struggle.
Greetz
/*Path to Images folder*/
$dir = WWW_ROOT . 'img' .DS. 'thumbnail';
/*Explode the name and ext*/
$f = explode('.',$data['image']['name']);
$ext = '.'.end($f);
/*Generate a Name in my case i use ID & slug*/
$filename = strtolower($id."-".$slug);
/*Associate the name to the extension */
$image = $filename.$ext;
/*Initialize you object and update you table in my case videos*/
$Videos->image = $image;
if ($this->Videos->save($Videos)) {
/*Save image in the thumbnail folders and replace if exist */
move_uploaded_file($data['image']['tmp_name'],$dir.DS.$filename.'_o'.$ext);
unlink($dir.DS.$filename.'_o'.$ext);
}
<?php
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Network\Exception\InternalErrorException;
use Cake\Utility\Text;
/**
* Upload component
*/
class UploadRegCompanyComponent extends Component
{
public $max_files = 1;
public function send( $data )
{
if ( !empty( $data ) )
{
if ( count( $data ) > $this->max_files )
{
throw new InternalErrorException("Error Processing Request. Max number files accepted is {$this->max_files}", 1);
}
foreach ($data as $file)
{
$filename = $file['name'];
$file_tmp_name = $file['tmp_name'];
$dir = WWW_ROOT.'img'.DS.'uploads/reg_companies';
$allowed = array('png', 'jpg', 'jpeg');
if ( !in_array( substr( strrchr( $filename , '.') , 1 ) , $allowed) )
{
throw new InternalErrorException("Error Processing Request.", 1);
}
elseif( is_uploaded_file( $file_tmp_name ) )
{
move_uploaded_file($file_tmp_name, $dir.DS.Text::uuid().'-'.$filename);
}
}
}
}
}
We're using https://github.com/josegonzalez/cakephp-upload with great success in our production app, and has done so for quite some time.
Has awesome support for using "Flysystem" (https://flysystem.thephpleague.com/) as well - which is abstractions from specific file system(s) - so moving from normal local file system to S3 is a no-brainer, or Dropbox or whatever place you want :-)
You can find related (high quality) plugins on file uploading right here: https://github.com/FriendsOfCake/awesome-cakephp#files - I've used "Proffer" with success as well, and it's by no means "almost done" or anything alike - both has all my recommendations and is in my eyes production ready!
I have an upload form, it works well, the photo is being uploaded but the problem is that the sfThumbnail plugin doesn't seem to work. No thumbnail is being generated. Here's my code:
// /lib/form/UploadForm.class.php
public function configure()
{
$this->setWidget('photo', new sfWidgetFormInputFileEditable(
array(
'edit_mode' => !$this->isNew(),
'with_delete' => false,
'file_src' => '',
)
));
$this->widgetSchema->setNameFormat('image[%s]');
$this->setValidator('photo', new sfValidatorFile(
array(
'max_size' => 5000000,
'mime_types' => 'web_images',
'path' => '/images/',
'required' => true,
'validated_file_class' => 'sfMyValidatedFileCustom'
)
));
And here's for the validator class
class sfMyValidatedFileCustom extends sfValidatedFile{
public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
{
$saved = parent::save($file, $fileMode, $create, $dirMode);
$thumbnail = new sfThumbnail(150, 150, true, true, 75, '');
$location = strpos($this->savedName,'/image/');
$filename = substr($this->savedName, $location+15);
// Manually point to the file then load it to the sfThumbnail plugin
$uploadDir = sfConfig::get('sf_root_dir').'/image/';
$thumbnail->loadFile($uploadDir.$filename);
$thumbnail->save($uploadDir.'thumb/'.$filename,'image/jpeg');
return $saved;
}
And my actions code:
public function executeUpload(sfWebRequest $request)
{
$this->form = new UploadForm();
if ($request->isMethod('post'))
{
$this->form->bind(
$request->getParameter($this->form->getName()),
$request->getFiles($this->form->getName())
);
if ($this->form->isValid())
{
$this->form->save();
return $this->redirect('photo/success');
}
}
}
I'm not 100% sure if I am doing it correctly but this is what I have seen from the docs and other examples.
You can't use $this->savedName because it's a protected value from sfValidatedFile. You should use $this->getSavedName() instead.
I don't understand this part:
$location = strpos($this->savedName,'/image/');
$filename = substr($this->savedName, $location+15);
Why do you extract the filename, when, finally, you re-add /image/ to it when load it with loadFile?
Any way, I made some change on your class. I didn't tested it but I think it should work.
class sfMyValidatedFileCustom extends sfValidatedFile
{
public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
{
$saved = parent::save($file, $fileMode, $create, $dirMode);
$filename = str_replace($this->getPath().DIRECTORY_SEPARATOR, '', $saved);
// Manually point to the file then load it to the sfThumbnail plugin
$uploadDir = $this->getPath().DIRECTORY_SEPARATOR;
$thumbnail = new sfThumbnail(150, 150, true, true, 75, '');
$thumbnail->loadFile($uploadDir.$saved);
$thumbnail->save($uploadDir.'thumb/'.$filename, 'image/jpeg');
return $saved;
}
So far I have been unable to successfully implement ACLs (permissions) in SabreDAV.
I have implemented SabreDAV in Code Igniter with my own Auth, Principal and CalDAV backend. This the actual code from the controller:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class CalDAV extends CI_Controller {
public function _remap() {
$this->load->library('SabreDAV');
$authBackend = new SabreDAV_DAV_Auth_Backend_Tank_Auth;
$principalBackend = new Sabre_DAVACL_PrincipalBackend_Click4Time;
$calendarBackend = new Sabre_CalDAV_Backend_Click4Time;
// Directory tree
$tree = array(
new Sabre_DAVACL_PrincipalCollection($principalBackend),
new Sabre_CalDAV_CalendarRootNode($principalBackend, $calendarBackend)
);
// The object tree needs in turn to be passed to the server class
$server = new Sabre_DAV_Server($tree);
// You are highly encouraged to set your WebDAV server base url. Without it,
// SabreDAV will guess, but the guess is not always correct. Putting the
// server on the root of the domain will improve compatibility.
$server->setBaseUri('/caldav/');
// Authentication plugin
$authPlugin = new Sabre_DAV_Auth_Plugin($authBackend, 'SabreDAV');
$server->addPlugin($authPlugin);
// CalDAV plugin
$caldavPlugin = new Sabre_CalDAV_Plugin();
$server->addPlugin($caldavPlugin);
// ACL plugin
$aclPlugin = new Sabre_DAVACL_Custom;
$server->addPlugin($aclPlugin);
// Support for html frontend
$browser = new Sabre_DAV_Browser_Plugin();
$server->addPlugin($browser);
$server->exec();
}
}
My current attempt at implementing permissions has been through my custom ACL Plugin:
<?php
class Sabre_DAVACL_Custom extends Sabre_DAVACL_Plugin {
public $allowAccessToNodesWithoutACL = false;
private function _getCurrentUserName() {
$authPlugin = $this->server->getPlugin('auth');
if (is_null($authPlugin)) return null;
return $authPlugin->getCurrentUser();
}
public function getACL($node) {
$user = $this->_getCurrentUserName();
$path = $node->getName();
if ($path == 'calendars' || $path == 'principals' || $path == 'root') {
return array(
array(
'privilege' => '{DAV:}read',
'principal' => 'principals/' . $user,
'protected' => true,
)
);
}
else if ($path == 'calendars/' . $user) {
return array(
array(
'privilege' => '{DAV:}read',
'principal' => 'principals/' . $user,
'protected' => true,
)
);
}
return array();
}
}
This code pretty much works except the second check which should authorize the user to see his or her own calendar(s). I am unable to get the full path name for $node.
This may be the wrong way to implement but I have been unable to find any documentation to confirm that this is the way to implement ACLs.
i'm using a different attempt, i extended the plugin, just like you did but then i replaced getSupportedPrivilegeSet($node) instead.
in sabredav 1.8.6 it looks like this:
public function getSupportedPrivilegeSet($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if ($node instanceof IACL) {
$result = $node->getSupportedPrivilegeSet();
if ($result)
return $result;
}
return self::getDefaultSupportedPrivilegeSet();
}
now you can use the classes instead of the path which i found more usefull, i.e.:
class DavCalAcl extends \Sabre\DAVACL\Plugin {
public function getSupportedPrivilegeSet($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if($node instanceof \Sabre\CalDAV\Calendar || $node instanceof \Sabre\CalDAV\CalendarObject) {
return array(
array(
'privilege' => '{DAV:}read',
'aggregates' => array(
array(
'privilege' => '{DAV:}read-acl',
'abstract' => true,
),
array(
'privilege' => '{DAV:}read-current-user-privilege-set',
'abstract' => true,
),
),
)
);
}
if ($node instanceof \Sabre\DAVACL\IACL) {
$result = $node->getSupportedPrivilegeSet();
if ($result)
return $result;
}
return self::getDefaultSupportedPrivilegeSet();
}
}
this is my current attempt to get iCal to recognize a calendar as read-only... i'm not quite there yet but maybe this will help you in better identifying the objects
if you want the absolute path of a node i guess you could always go to the root search it for your current node and by doing so recording the path which took you there. as far as i checked the nodes in sabredav do not support a parent or a root property.
[UPDATE]
the best way seems to be to override getACL in the plugin. here you can test for the node's class and return what you really want on instead of the stuff which is returned by the default objects (for instance look at UserCalendars->getACL().
here's my working solution for read-only enforcement based on the object types:
class DavCalAcl extends \Sabre\DAVACL\Plugin {
/**
* Returns the full ACL list.
*
* Either a uri or a DAV\INode may be passed.
*
* null will be returned if the node doesn't support ACLs.
*
* #param string|DAV\INode $node
* #return array
*/
public function getACL($node) {
if (is_string($node)) {
$node = $this->server->tree->getNodeForPath($node);
}
if (!$node instanceof \Sabre\DAVACL\IACL) {
return null;
}
if( $node instanceof \Sabre\CalDAV\Calendar ||
$node instanceof \Sabre\CalDAV\CalendarObject ||
$node instanceof \Sabre\CalDAV\UserCalendars
) {
$acl = array(
array(
'privilege' => '{DAV:}read',
'principal' => $node->getOwner(),
'protected' => true,
),
);
} else {
$acl = $node->getACL();
}
foreach($this->adminPrincipals as $adminPrincipal) {
$acl[] = array(
'principal' => $adminPrincipal,
'privilege' => '{DAV:}all',
'protected' => true,
);
}
return $acl;
}
}