Zend_File_Transfer w/multiple files does not upload equally - zend-framework

Weird title, yes, but the problem is simple; simply aggrevating. I have a form, that I built without using Zend_Form, and it has two file uploads:
<input name="image" type="file" />
<input name="file" type="file" />
Here is the chunk of code from my controller that is handling the upload. There's actually a little more, but this is the relevant piece:
$data['image'] = (isset($_FILES["image"]) && $_FILES["image"]["name"] ? $_FILES["image"]["name"] : NULL);
$data['file'] = (isset($_FILES["file"]) && $_FILES["file"]["name"] ? $_FILES["file"]["name"] : NULL);
$options = array('ignoreNoFile' => TRUE);
$upload = new Zend_File_Transfer();
$upload->setOptions($options)
->addFilter('Rename', array('target' => RESOURCES_IMG . $data['image'], 'overwrite' => TRUE), 'image')
->addFilter('Rename', array('target' => RESOURCES_FILES . $data['file'], 'overwrite' => TRUE), 'file')
->addValidator('ImageSize', false, array('minwidth' => 100,
'maxwidth' => 100,
'minheight' => 100,
'maxheight' => 100), 'image')
->addValidator('Extension', false, 'jpg', 'image');
if (!$upload->isValid())
{
echo '<h1>Oops</h1><p>Please correct the following errors: <hr /></p>';
foreach ($upload->getMessages() as $key => $val)
{
echo '<p><strong>' . $key . '</strong><br />' . $val . '</p>';
}
die;
}
else
{
$upload->receive();
} // if (!$upload->isValid())
It's pretty straight forward. The $data stuff is just me grabbing the filename if it's there or setting the variable to NULL. I have my addFilter() and addValidator() segmented out to only affect their relevant files in this case "image" or "file" - the names of the form fields.
The "file" upload always works! However, the "image" upload doesn't and what's more it puts the temporary file into the RESOURCES_FILES directory which makes no sense at all. So that directory has PDFs and whatever else in addition to files like php8TJT13, phpXmOzQM, etc.
I have been staring at this code and searching through Stack Overflow and whatever Google will turn up and I can't find anyone having this problem. Help!

Alright, so I did more digging and it turns out there may be an issue with the way I was chaining addFilter() so I decided to move in a different direction, trying to isolate each file and handle it's upload individually. So far it appears to be working. Here is the revised code:
$data['image'] = (isset($_FILES["image"]) && $_FILES["image"]["name"] ? $_FILES["image"]["name"] : NULL);
$data['file'] = (isset($_FILES["file"]) && $_FILES["file"]["name"] ? $_FILES["file"]["name"] : NULL);
$upload = new Zend_File_Transfer();
$files = $upload->getFileInfo();
$options = array('ignoreNoFile' => TRUE);
$upload->setOptions($options);
foreach ($files as $field => $contents)
{
if(!strlen($contents["name"]))
{
continue;
}
// upload instructions for image
if ($field == 'image')
{
$upload->addFilter('Rename', array('target' => RESOURCES_IMG . $data['image'], 'overwrite' => TRUE), 'image')
->addValidator('ImageSize', false, array('minwidth' => 100,
'maxwidth' => 100,
'minheight' => 100,
'maxheight' => 100), 'image')
->addValidator('Extension', false, 'jpg', 'image');
}
// upload instructions for file
if ($field == 'file')
{
$upload->addFilter('Rename', array('target' => RESOURCES_FILES . $data['file'], 'overwrite' => TRUE), 'file');
}
if(!$upload->receive($field)) {
echo '<h1>Oops</h1><p>Please correct the following errors: <hr /></p>';
foreach ($upload->getMessages() as $key => $val)
{
echo '<p><strong>' . $key . '</strong><br />' . $val . '</p>';
}
die;
//return;
}
} // foreach
Pseudo Explanation
I use the getFileInfo() to grab an array of the files available to me then I loop over each. At the beginning of my first for loop I check to see if this file has a name, if it doesn't have a name I assume that field was left blank and is NULL so I tell the loop to skip over that and continue.
Once I'm in the loop I'm just matching my upload directives with the appropriate form field using a simple conditional. The rest should be fairly self-explanatory if you're into Zend stuff.
Hopefully this helps someone else that was in my predicament. If you are a Zend guru maybe you can comment on my solution or fix the bug that's causing the issue. There may be a more "Zend" way of doing it, but it's working now and that feels damn good.
References
Why I thought it was the chaining of the addFilter() method, see the note under Example #3 (below):
Note: Note that even though setting the same filter multiple times is allowed, doing so can lead to issues when using different options for the same filter.
http://framework.zend.com/manual/1.11/en/zend.file.transfer.filters.html
A random blog article that inspired me to try isolating each, I'm calling it, "upload directive" although I'm not sure if that's what it's called:
http://www.pc-freak.net/blog/tag/uploading-multiple-files-from-a-form-with-zend-framework-zf-storing-uploaded-zf-files-with-unique-name/

Related

My rows are wonky!

I am building a theme template page that calls up all the child categories of a particular parent and displays them so that they look like this:
The only trouble is that when any row has less than 3 posts, it looks like this:
I need to display 1-3 posts and move on to the next category if there are either more OR less than 3 posts, and not have it look like crap.
$taxonomy = 'category'; // e.g. post_tag, category
$param_type = 'category__in'; // e.g. tag__in, category__in
$term_args=array(
'orderby' => 'name',
'order' => 'ASC',
'child_of' => 13
);
$terms = get_terms($taxonomy,$term_args);
if ($terms) {
foreach( $terms as $term ) {
$args=array(
"$param_type" => array($term->term_id),
'post_type' => 'candidate',
'post_status' => 'publish',
'showposts' => -1,
'caller_get_posts'=> 1
);
$my_query = null;
$my_query = new WP_Query($args);
if( $my_query->have_posts() ) {
echo '<div class="val-postcontent val-post"><h4 >' . $term->name. ' Candidates</h4></div> ';
while ($my_query->have_posts()) : $my_query->the_post();
get_template_part('content', 'overview');
endwhile;
echo '<div class="test"><a href="' . get_category_link( $term->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $term->name ) . '" ' . '>Click here to view all ' . $term->name. ' Candidates</a></div>';
}
}
}
I too belive this is a CSS issue, so it probably belongs on StackExchange instead, but here it goes:
The easiest, quickest (and probably ugliest) fix is to add <div style="display:block; clear: both;"> before each <div class="val-postcontent val-post">.
A quick way to make this a little bit cleaner: move the display:block; clear: both; into a separate css class, for example .clearfix {...}.
edit: I was to quick on the trigger. The div should be added before the div

Laravel: Multiple File Upload, Input::hasFile(key) always false

i generated a multiple upload form with the former generator tool from https://github.com/Anahkiasen/former.
{{ Former::files('file')->accept('image')->required(); }}
that results in
<input multiple="true" accept="image/*" required="true" id="file[]" type="file" name="file[]">
After I've submit the form Ive figured out that Input::hasFile('file') always returns false whilst Input:has('file') returns true.
What i've tried until now:
Log::info(Input::file('file')); <-- empty
foreach(Input::file('file') as $file) <-- Invalid argument supplied for foreach()
Log::info("test");
if(Input::has('file'))
{
if(is_array(Input::get('file')))
foreach ( Input::get('file') as $file)
{
Log::info($file); <-- returns the filename
$validator = Validator::make( array('file' => $file), array('file' => 'required|image'));
if($validator->fails()) {
...
}
}
}
Of course, the validator always fails cause Input::get('file') does not return a file object. How do I have to modify my code to catch the submited files?
Thanks for the help, the answer from Kestutis made it clear. The common way to define a file form in Laravel is
echo Form::open(array('url' => 'foo/bar', 'files' => true))
This Options sets the proper encryption type with enctype='multipart/form-data'.
With the laravel form builder "Former" you have to open the form with
Former::open_for_files()
After that u can validate the form in the common way.
if(Input::hasFile('files')) {
Log::info(Input::File('files'));
$rules = array(
...
);
if(!array(Input::File('files')))
$rules["files"] = 'required|image';
else
for($i=0;$i<count(Input::File('files'));$i++) {
$rules["files.$i"] = 'required|image';
}
$validation = Validator::make(Input::all(), $rules);
if ($validation->fails())
{
return ...
}
else {
// everything is ok ...
}

Phalcon Paginator error: Syntax error, unexpected EOF

my problem is, every time I click in the paginator link in the view, the controller returns me this error:
Syntax error, unexpected EOF
What is this? EOF?
My controller:
$domicilios = Domicilios::find();
$paginator = new \Phalcon\Paginator\Adapter\Model(
array(
"data" => $domicilios,
"limit"=> 5,
"page" => $currentPage
)
);
$pagina = $paginator->getPaginate();
$this->view->setVar("estado", $estado);
$this->view->setVar("pagina", $pagina);
The content in the model Domicilios is returning right, but why the paginator keeps returning this error?
Thanks in advance!
EOF is end of file. there might be several issues. 1stly if you upload this file to server, there might be problems with upload process and file is not fully uploaded and you have broken end of file (EOF).
try converting your php file to utf8. you can do it with notepad++ and many other programs.
here are my working pagination:
$page = $this->request->get('page', 'int', 1);
$this->view->page = $page;
if ($page < 1) {
$page = 1;
}
$user = $this->session->get('auth');
$questions = Model_UserQuestion::find(array(
'user_id=:user_id:',
'bind' => array('user_id' => $user['id']),
"order" => "id DESC",
));
// Create a Model paginator, show 10 rows by page starting from $currentPage
$paginator = new \Phalcon\Paginator\Adapter\Model(
array(
"data" => $questions,
"limit" => $this->config->application->itemsPerPage,
"page" => $page
)
);
$page = $paginator->getPaginate();
$this->view->questions = $page->items;
notice that to get items you have to use this:
$page->items

How to use Zend_File_Transfer?

I have been using normal file upload element to upload files and validate them. But recently, I found out that implementing a Zend_file_tranfer gives much control over the file.
I am searched Everywhere in the internet searching for a simple example to get started with it, but none of them show how they are linked to the element. I dont know where to create the object of Zend_File_Transfer, and how to add it to the element? I basically dont know, how to use it.
Can anyone give me a beginners example of using zend_File_tranfers, in both zend_form and Zend_Controller_Action
In form:
class Application_Form_YourFormName extends Zend_Form
{
public function __construct()
{
parent::__construct($options);
$this->setAction('/index/upload')->setMethod('post');
$this->setAttrib('enctype', 'multipart/form-data');
$upload_file = new Zend_Form_Element_File('new_file');
$new_file->setLabel('File to Upload')->setDestination('./tmp');
$new_file->addValidator('Count', false, 1);
$new_file->addValidator('Size', false, 67108864);
$new_file->addValidator('Extension', false, Array('png', 'jpg'));
$submit = new Zend_Form_Element_Submit('submit');
$submit->setLabel('Upload');
$this->addElements(array($upload_file, $submit));
}
}
In controller:
class Application_Controller_IndexController extends Zend_Controller_Action
{
public function uploadAction()
{
$this->uform = new Application_Form_YourFormName();
$this->uform->new_file->receive();
$file_location = $this->uform->new_file->getFileName();
// .. do the rest...
}
}
When you create your form do something like this in your form:
$image = $this->getElement('image');
//$image = new Zend_Form_Element_File();
$image->setDestination(APPLICATION_PATH. "/../data/images"); //!!!!
$extension = $image->getFileName();
if (!empty($extension))
{
$extension = #explode(".", $extension);
$extension = $extension[count($extension)-1];
$image->addFilter('Rename', sprintf('logo-%s.'.$extension, uniqid(md5(time()), true)));
}
$image
->addValidator('IsImage', false, $estensioni)//doesn't work on WAMPP/XAMPP/LAMPP
->addValidator('Size',array('min' => '10kB', 'max' => '1MB', 'bytestring' => true))//limit to 200k
->addValidator('Extension', false, $estensioni)// only allow images to be uploaded
->addValidator('ImageSize', false, array(
'minwidth' => $img_width_min,
'minheight' => $img_height_min,
'maxwidth' => $img_width_max,
'maxheight' => $img_height_max
)
)
->addValidator('Count', false, 1);// ensure that only 1 file is uploaded
// set the enctype attribute for the form so it can upload files
$this->setAttrib('enctype', 'multipart/form-data');
Then when you submit your form in your controller:
if ($this->_request->isPost() && $form->isValid($_POST)) {
$data = $form->getValues();//also transfers the file
....
Here are some links that can help you.
Zend Documentation
Same Question on SO
Step By Step Toturial
Another Useful Link

Drupal - Include more than one user_profile_form on a page

Edit:
I think it is because the action is the same or something. I tried to modify the action using this:
function mytheme_user_profile_form($form) {
global $user;
$uid = $user->uid;
//print '<pre>'; print_r($form); print '</pre>';
$category = $form['_category']['#value'];
switch($category) {
case 'account':
$form['#action'] = '/user/'.$uid.'/edit?destination=user/'.$uid;
break;
case 'education':
$form['#action'] = '/user/'.$uid.'/edit/education?destination=user/'.$uid;
break;
case 'experience':
$form['#action'] = '/user/'.$uid.'/edit/experience?destination=user/'.$uid;
break;
case 'publications':
$form['#action'] = '/user/'.$uid.'/edit/publications?destination=user/'.$uid;
break;
case 'conflicts':
$form['#action'] = '/user/'.$uid.'/edit/conflicts?destination=user/'.$uid;
break;
}
//print '<pre>'; print_r($form); print '</pre>';
//print $form['#action'];
$output .= drupal_render($form);
return $output;
}
But, the form action, when the form is actually rendered is unchanged. They're all /user/%uid
Can I modify the form action?
I am including several different "categories" of the user profile form on one page, and the code will correctly output the forms I'm specifying. Each form is in a separate collapsible div.
My problem is twofold.
(1) The existing values for the fields aren't pre-populated and
(2) Clicking on "Save" for one section will result in a warning: Email field is required, regardless of which form you're actually saving
I am pretty sure that for problem #2, it is because the name of the button is the same in all cases, as is the form id.
print '<h3>– Account Settings</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'account'));
print '</div>';
print '<h3>– My Info</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'Personal'));
print '</div>';
print '<h3>– Experience</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'experience'));
print '</div>';
print '<h3>– Education</h3>';
print '<div class="expand">';
print(drupal_get_form('user_profile_form', $user, 'education'));
print '</div>';
Problem #1: ? Could you post the html source?
For problem #2:
OK, I'll step through the code here:
The validation handler for the user profile form (user_profile_form_validate()) calls
user_module_invoke('validate', $form_state['values'], $form_state['values']['_account'], $form_state['values']['_category']);
Which looks like
<?php
/**
* Invokes hook_user() in every module.
*
* We cannot use module_invoke() for this, because the arguments need to
* be passed by reference.
*/
function user_module_invoke($type, &$array, &$user, $category = NULL) {
foreach (module_list() as $module) {
$function = $module .'_user';
if (function_exists($function)) {
$function($type, $array, $user, $category);
}
}
}
?>
So, the validation handler for this form is going through every module looking for user hook functions and calling them with $type = 'validate'. (Note that 'category' param is optional here - contrib modules are not required to use it)
Let's look at user.module's user hook as an example to see what happens:
function user_user($type, &$edit, &$account, $category = NULL) {
if ($type == 'view') {
$account->content['user_picture'] = array(
'#value' => theme('user_picture', $account),
'#weight' => -10,
);
if (!isset($account->content['summary'])) {
$account->content['summary'] = array();
}
$account->content['summary'] += array(
'#type' => 'user_profile_category',
'#attributes' => array('class' => 'user-member'),
'#weight' => 5,
'#title' => t('History'),
);
$account->content['summary']['member_for'] = array(
'#type' => 'user_profile_item',
'#title' => t('Member for'),
'#value' => format_interval(time() - $account->created),
);
}
if ($type == 'form' && $category == 'account') {
$form_state = array();
return user_edit_form($form_state, (isset($account->uid) ? $account->uid : FALSE), $edit);
}
//<-- LOOK HERE -->
if ($type == 'validate' && $category == 'account') {
return _user_edit_validate((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'submit' && $category == 'account') {
return _user_edit_submit((isset($account->uid) ? $account->uid : FALSE), $edit);
}
if ($type == 'categories') {
return array(array('name' => 'account', 'title' => t('Account settings'), 'weight' => 1));
}
}
So, it is only supposed to validate if the category == 'account'
In the function _use_edit_validate, we find:
// Validate the e-mail address:
if ($error = user_validate_mail($edit['mail'])) {
form_set_error('mail', $error);
}
There's your error message.
Since that form is only supposed to validate when the category == 'account', and your problem (#2) seems to be that it always validates regardless of the category, maybe your forms are not being rendered as unique form instances? Drupal might be rendering a complete form each time, and just setting a hidden form value to whatever the category is (like in this form's definition function in user_pages.inc $form['_category'] = array('#type' => 'value', '#value' => $category);)
It would be helpful to see the actual html source output.
==EDIT 10-15-09 in response to updated question===
OK, it looks like your method (editing $form['#action'] manually in the theme layer) may not be possible (see this post for reference). If you want to alter the form action you need to write a custom module that implements hook_form_alter() (it won't work in a theme template file). This function allows you to modify how a form is rendered, in your case the user modification form. There are more details on form modification here.
I am not 100% sure that's what you want to do though; (since it looks like you already must create a module) perhaps you want to hook into hook_user() instead; this function "... allows modules to react when operations are performed on user accounts.". You may be able to react to the category in this function and block/allow whichever user changes you like.
However, if it's just email address validation that is the problem, and if you are dealing with existing users, why don't you just make sure the email address is set before you save?