I have created normal Symfony form. However I require additional files to be uploaded (photos, certificates) which I handle by AJAX and are not retrieved via Symfony form.
Instead file upload is handled in separate controllers actions via file bag.
I would like to limit the maximum file size (only for this action).
If the upload was handled by classic form I would use the file constraint
but this way I do not now how to apply it.
I check mime-type and successful upload by methods on UploadedFile, however the documentation for method for retrieving the size is in a way discouraging (UploadedFile#method_getClientSize).
Is there a way how to use FileValidator/File constraint without the form?
I have got inspired by actual implementation of FileValidator:
$file = $request->files->get('file');
$path = $file->getPathname();
$size = round(filesize($path) / 1000000, 2);
$limit = (int) $constraint->maxSize;
if ($size > $limit) {
//Add violation
}
This solution works and is probably better then use getClientSize().
Related
I really hope someone can help me.
I need to be able to serve banners in categories which are dependant on a session variable - and can't find a component which does that. So I'd like to extend the Joomla Banner component in order to select banners based on a session variable which contains the category path.
The correct session variable is being stored correctly.
In order to do this I added an option in the banners module .xml to allow for a session variable and the name of the session variable. This is being stored correctly in the module table within the params field along with the other module parameters.
Then I started on the
components > banners > com_banners > models > banners.php
by adding two lines of code in getListQuery where the SQL is assembled. They are:
$sess_vars = $this->getState('filter.sess_vars');
$sess_vars_name = $this->getState('filter.sess_vars_name');
But both variables contain nothing even though the ones the component already has can be retrieved fine. Without a doubt I need to change something somewhere else as well - but just can't figure out what to do.
Any help would be greatly appreciated.
The first thing to do is not hack the core files, hacking the core prevents you from using the built-in update feature to apply the regular bug fixes and security patches released by Joomla! (e.g. the recently released 2.5.9 version).
Rather make a copy of them and modify it so it's called something else like com_mybanners. Apart from the folder name and the entry point file (i.e. banners.php becomes mybanners.php) you will also want to update the components banners.xml to mybanners.php.(You will need to duplicate and modify both the front end /components/com_banners/ and /administrator/components/mybanners.php.)
Because of the way Banners work (i.e. banners are displayed in a module) you will also need to duplicate and modify /modules/mod_banners/,/modules/mod_banners/mod_banners.php and /modules/mod_banners/mod_banners.xml. Changing mod_banners to mod_mybanners in each location.
In Joomla! components the state is usually populated when JModel is instantiated, however, in this case the component is really about managing banners and recording clicks the display is handled by mod_banners. So, you will want to add some code to mod_mybanners.php to use the session variables you want to act on. Normally when a models state is queried you will collect the variables via JInput and add them to your object's state e.g.
protected function populateState()
{
$jApp = JFactory::getApplication('site');
// Load state from the request.
$pk = $jApp->input->get('id',0,'INT');
$this->setState('myItem.id', $pk);
$offset = $jApp->input->get('limitstart',0,'INT');
$this->setState('list.offset', $offset);
// Load the parameters.
$params = $app->getParams();
$this->setState('params', $params);
// Get the user permissions
$user = JFactory::getUser();
if ((!$user->authorise('core.edit.state', 'com_mycomponent')) && (!$user->authorise('core.edit', 'com_mycomponent')))
{
$this->setState('filter.published', 1);
$this->setState('filter.archived', 2);
}
}
The populateState() method is called when a state is read by the getState method.
This means you will have to change your copy of /components/com_banners/models/banner.php to capture your variables into the objects state similar to my example above.
From there it's all your own code.
You can find all of this information in the Developing a Model-View-Controller tutorial on the Joomla Doc's site
Here is my BrandController.php
https://gist.github.com/a958926883b9e7cc68f7#file-brandcontroller-php-L53
I've gone through all my files of my custom module, and compared them to the one given from the custom module maker, and I couldn't find much differences.
Are you attempting to upload multiple files? If you're using multiple fileupload elements with the same name you'll get an array of items.
So when the following line is called,
//this way the name is saved in DB
$data['filename'] = $_FILES['filename']['name'];
It will have the value
["name"]=>array(2) {
[0]=>string(9)"file0.txt"
[1]=>string(9)"file1.txt"
}
you'll need to update the code to loop through each $_FILES['filename']['name'] and upload and save the files separately.
You may unknowingly uploaded multiple files. If you that is not your intention, you may check your in your HTML and check the name attribute of the tag. It must not be an array (like this).
<input type="file" name="my_files[]" />
If you only see Array() in your database, it means you are indeed uploading a multiple files. You can process them by using loops.
If you are really sure that you are uploading 1 image, you may follow #Palanikumar's suggestion. Use a print_r() and display the $_FILES and paste it here. IF you don't want to use that, You can use
json_encode($the-data-you-are-going-to-insert-to-the-database);
If you don't know where to put the print_r() function, you may put it after line 56 of this file.
https://gist.github.com/desbest/a958926883b9e7cc68f7#file-brandcontroller-php-L53
if(isset($_FILES['filename']['name']) && $_FILES['filename']['name'] != '') {
print_r($_FILES);
die;
If saveAction() is being called inside an ajax function you need to log the ajax response. Assuming you are using jquery..
$ajaxResponse = $.POST({...});
console.log($ajaxResponse.responseText);
Then, you you can view it inside a browser's console. If nothing appears, you may use a non-async request
$ajaxResponse = $.POST({
// your options,
// your another option,
async: FALSE
});
Usually file upload will return in array format. So that each uploaded file will have the information like name, type, size, temporary name, error. You can get the file information using print function (print_r($_FILES)). So if you want to display name of the file you have to use something like this $_FILES['filename']['name']
Use print function and debugging tool then save file information using loops.
For more info please check here.
You aren't setting the enctype of the form so the image will never be sent. updated the code to
$form = new Varien_Data_Form(array( 'enctype' => 'multipart/form-data'));
In my Symfony project I'm trying to provide a "save as template"-button for an embedded Form. The embedded form contains dynamic embedded forms itself.
Example:
The user should be able to save the template without saving the whole form. So i'm going to use AJAX to achieve this (as I already did, for the dynamic add-behavior).
The actual problem is that Symfony names the form in dependence on the parent form, e.g.
<input name="Project[Workflow][1][name]" />
But the template isn't related to "Project" at all. On the other hand, this naming format is required later, when saving the whole form.
Sending the whole form to the server might be a solution, but I think it's a bad practice / overkill / waste of bandwidth.
Is there a common way how to do this?
If not, do you have a basic approach in mind?
Regards,
Uli
symfony sfForms take 2 arrays on the bind method, you don't really need to take them from the request.
since you have several WorkflowForms there is a loop involved!
$formData = $request->getParameter('Project'); // you could do Project['Workflow'] except for symfony 1.4
foreach ($formData['Workflow'] as $embeddedData)
{
$formFiles = $request->getFiles('Project');
$embeddedFiles = $formFiles['Workflow'];
$form = new WorkflowForm();
$form->bind($embeddedData, $embeddedFiles);
if ($form->isValid())
{
// do your thing
// ...
$form->save();
}
}
then you process each form as you would usually do on // do your thing
I'm working on an AIR application which generates a dynamic client presentation, pulling all necessary data from a PHP framework API. In the process, I download a large number of images and store them locally in the user's app-storage (air.File.applicationStorageDirectory).
Side note: the HTML view I am dynamically populating is located in an IFRAME sandbox.
I have a parsing script which attempts to take JSON data and populate the page with the necessary fields. Many of these fields are images that I need to locally reference. I thought I might be able to simply generate the URL using <img src="app-storage:/path/to/img.jpg"> but it doesn't seem to actually load the image. My guess is AIR doesn't handle app-storage: url references dynamically. Is there a work-around for this? Could I perhaps use jQuery and load()?
Here is the current code I am using which is not working:
var pos = filename.lastIndexOf(".");
if (pos != -1) {
ext = filename.substr(pos + 1, filename.length);
switch (ext) {
case 'gif':
case 'jpg':
case 'jpeg':
case 'png':
default:
// update the source value
$field.attr('src', 'app-storage:' + filename);
break;
}
}
I thought I might be on the right track because the return result of
air.File.applicationStorageDirectory('test')
was app-storage:/test
Any help would be greatly appreciated!
The solution ended up being that I had to properly set the IFRAME to have Application security level access, granting it privileges to use handle app-storage urls properly. For those interested in knowing how you can go about doing this, the first step is to simply have the IFRAME file you wish to load directly in the application's main directory:
<iframe id="childFrame" src="child.html" documentRoot="app:/" allowcrossDomainxhr="true" width="100%" height="100%"></iframe>
The key difference in this sandbox is that it doesn't have the parameter sandboxRoot.
It's worth noting that I never once experienced any security errors during any of my testing. It seemed as though the app-storage URL was just not properly being handled by AIR itself.
people talking than you need to allow security policy there.
I would like to call a Ruby script when a user uploads an image to my Drupal content-type. I have a CCK image field that serves as the main image, and ImageCache takes care of resizing and creating thumbnails for me.
I have a Ruby script that does some transformations to the image, however I don't exactly know how to call it (no experience with Ruby really). Basically the script applies some image transforms and then generates a new image.
My question is how to call this script from Drupal...is there some sort of hook regarding the CCK image upload that I would hijack?
ImageField uses the same API as FileField. Therefore, you could add a custom validator for your upload field, which would do some checks on the image (like calling a ruby script).
I described that some time ago on Drupal.org, see: http://drupal.org/node/546146
However, for your convenience, here the code.
First, define a validator for the upload form:
function example_form_alter(&$form, $form_state, $form_id) {
if ($form_id != 'ID_OF_YOUR_FORM')
return;
$form['FIELDNAME'][0]['#upload_validators']['example_FUNCTIONNAME'] = array();
return $form;
}
Second, implement the validator function:
function example_FUNCTIONNAME($field) {
// variable for error messages
$errors = array();
// do some processing on the field
$filepath = $field->filepath;
...
// in case of error, add error message
$errors[] = t('Validation failed, because...');
return $errors;
}
Put this code in a custom module, but make sure that your module is called after FileField and ImageField (adjust weight in system table).
Update: There is another way to hook into it. You can use hook_nodeapi to react on operation "presave". This also allows you to call a script on the content of the uploaded field.