I want to upload an image with Zend Framework version 1.9.6. The uploading itself works fine, but I want a couple of other things as well ... and I'm completely stuck.
Error messages for failing to upload an image won't show up.
If a user doesn't enter all the required fields but has uploaded an image then I want to display the uploaded image in my form. Either as an image or as a link to the image. Just some form of feedback to the user.
I want to use Zend_ Validate_ File_ IsImage. But it doesn't seem to do anything.
And lastly; is there some automatic renaming functionality?
All ideas and suggestions are very welcome. I've been struggling for two days now.
These are simplified code snippets:
myform.ini
method = "post"
elements.title.type = "text"
elements.title.options.label = "Title"
elements.title.options.attribs.size = 40
elements.title.options.required = true
elements.image.type = "file"
elements.image.options.label = "Image"
elements.image.options.validators.isimage.validator = "IsImage"
elements.submit.type = "submit"
elements.submit.options.label = "Save"
TestController
<?php
class Admin_TestController extends Zend_Controller_Action
{
public function testAction ()
{
$config = new Zend_Config_Ini(MY_SECRET_PATH . 'myform.ini');
$f = new Zend_Form($config);
if ($this->_request->isPost())
{
$data = $this->_request->getPost();
$imageElement = $f->getElement('image');
$imageElement->receive();
//$imageElement->getValue();
if ($f->isValid($data))
{
//save data
$this->_redirect('/admin');
}
else
{
$f->populate($data);
}
}
$this->view->form = $f;
}
}
?>
My view just echo's the 'form' variable.
First, put this at the start of your script:
error_reporting(E_ALL);//this should show all php errors
I think the error messages are missing from the form because you re-populate the form before you display it. I think that wipes out any error messages. To fix that, remove this part:
else
{
$f->populate($data);
}
To show the uploaded image in the form, just add a div to your view template, like this:
<div style="float:right"><?=$this->image?></div>
If the image uploaded ok, then populate $view->image with an img tag.
As for automatic re-naming, no, it's not built in, but it's very easy. I'll show you how below.
Here's how I handle my image uploads:
$form = new Zend_Form();
$form->setEnctype(Zend_Form::ENCTYPE_MULTIPART);
$image = new Zend_Form_Element_File('image');
$image->setLabel('Upload an image:')
->setDestination($config->paths->upload)
->setRequired(true)
->setMaxFileSize(10240000) // limits the filesize on the client side
->setDescription('Click Browse and click on the image file you would like to upload');
$image->addValidator('Count', false, 1); // ensure only 1 file
$image->addValidator('Size', false, 10240000); // limit to 10 meg
$image->addValidator('Extension', false, 'jpg,jpeg,png,gif');// only JPEG, PNG, and GIFs
$form->addElement($image);
$this->view->form = $form;
if($this->getRequest()->isPost())
{
if(!$form->isValid($this->getRequest()->getParams()))
{
return $this->render('add');
}
if(!$form->image->receive())
{
$this->view->message = '<div class="popup-warning">Errors Receiving File.</div>';
return $this->render('add');
}
if($form->image->isUploaded())
{
$values = $form->getValues();
$source = $form->image->getFileName();
//to re-name the image, all you need to do is save it with a new name, instead of the name they uploaded it with. Normally, I use the primary key of the database row where I'm storing the name of the image. For example, if it's an image of Person 1, I call it 1.jpg. The important thing is that you make sure the image name will be unique in whatever directory you save it to.
$new_image_name = 'someNameYouInvent';
//save image to database and filesystem here
$image_saved = move_uploaded_file($source, '/www/yoursite/images/'.$new_image_name);
if($image_saved)
{
$this->view->image = '<img src="/images/'.$new_image_name.'" />';
$form->reset();//only do this if it saved ok and you want to re-display the fresh empty form
}
}
}
First, have a look at the Quick Start tutorial. Note how it has an ErrorController.php that will display error messages for you. Also note how the application.ini has these lines to cause PHP to emit error messages, but make sure you're in the "development" environment to see them (which is set in public/.htaccess).
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
Second, ZF has a renaming filter for file uploads:
$upload_elt = new Zend_Form_Element_File('upload');
$upload_elt
->setRequired(true)
->setLabel('Select the file to upload:')
->setDestination($uploadDir)
->addValidator('Count', false, 1) // ensure only 1 file
->addValidator('Size', false, 2097152) // limit to 2MB
->addValidator('Extension', false, 'doc,txt')
->addValidator('MimeType', false,
array('application/msword',
'text/plain'))
->addFilter('Rename', implode('_',
array($this->_user_id,
$this->_upload_category,
date('YmdHis'))))
->addValidator('NotExists', false, $uploadDir)
;
Some of the interesting things above:
mark the upload as required (which your .ini doesn't seem to do)
put all the uploads in a special directory
limit file size and acceptable mime types
rename upload to myuser_category_timestamp
don't overwrite an existing file (unlikely, given our timestamp scheme, but let's make sure anyway)
So, the above goes in your form. In the controller/action that receives the upload, you could do this:
$original_filename = $form->upload->getFileName(null, false);
if ($form->upload->receive()) {
$model->saveUpload(
$this->_identity, $form->upload->getFileName(null, false),
$original_filename
);
}
Note how we capture the $original_filename (if you need it) before doing receive(). After we receive(), we do getFileName() to get the thing that the rename filter picked as the new filename.
Finally, in the model->saveUpload method you could store whatever stuff to your database.
Make sure your view also outputs any error messages that you generate in the controller: loading errors, field validation, file validation. Renaming would be your job, as would other post processing such as by image-magick convert.
When following lo_fye's listing I experienced problems with custom decorators.
I do not have the default File Decorator set and got the following exception:
Warning: Exception caught by form: No file decorator found... unable to render file element Stack Trace:
The Answer to this is that one of your decrators must implement the empty interface Zend_Form_Decorator_Marker_File_Interface
Also sometimes it happens to bug when using an ajax request. Try it without an ajax request and don't forget the multipart form.
Related
i want to create form with php that have multiple part and type of data. Such as:
Input Text (name,title, description,etc)
Input image (header_img)
Input Multiple image (slider)
The point is i want to create a lot of data include upload file in one page using php.
In post method, i try standard logic, upload one by one of image with if else logic, with a lot of if else logic and different name and insert it in each field of database (one field in one field database) huft....
if($_FILES['imghead']['size']!=0){
// run upload method
}
And for edit , i try it manually, same as post method, using if else for each field. for example:
if($_FILES['imghead']['size']!=0){
// run upload method
}
if($_FILES['slider1']['size']!=0){
// run upload method
}
if($_FILES['slider2']['size']!=0){
// run upload method
}
if($_FILES['slider3']['size']!=0){
// run upload method
}
// etc
But the problem is, i think my method is not really good, its not effective and i must write a lot of code and check them one bu one with if else logic.
My Question:
Do you know how to optimize my logic to real simple code? specially CRUD.
i have try grocery crud but i need more feature like multiple images upload
There is a way to implement multiple images upload with grocerycrud, in the controller you need to asign a different name method to every upload field that you need and then just copy paste the main method in the Grocery_CRUD.php file and change the name to the same that you assigned
Controller code:
$crud->set_field_upload('file1','assets/uploads');
$crud->set_another_field_upload('file2','assets/uploads');
This is the code that you need to copy, (route:htdocs\app_name\application\libraries\Grocery_CRUD.php)
public function set_field_upload($field_name, $upload_dir = '')
{
$upload_dir = !empty($upload_dir) && substr($upload_dir,-1,1) == '/'
? substr($upload_dir,0,-1)
: $upload_dir;
$upload_dir = !empty($upload_dir) ? $upload_dir : 'assets/uploads/files';
/** Check if the upload Url folder exists. If not then throw an exception **/
if (!is_dir(FCPATH.$upload_dir)) {
throw new Exception("It seems that the folder \"".FCPATH.$upload_dir."\" for the field name
\"".$field_name."\" doesn't exists. Please create the folder and try again.");
}
$this->upload_fields[$field_name] = (object) array(
'field_name' => $field_name,
'upload_path' => $upload_dir,
'encrypted_field_name' => $this->_unique_field_name($field_name));
return $this;
}
Just paste it below and change the function name with the same name assigned in your controller:
public function set_another_field_upload($field_name, $upload_dir = '')
{
$upload_dir = !empty($upload_dir) && substr($upload_dir,-1,1) == '/'
? substr($upload_dir,0,-1)
: $upload_dir;
$upload_dir = !empty($upload_dir) ? $upload_dir : 'assets/uploads/files';
/** Check if the upload Url folder exists. If not then throw an exception **/
if (!is_dir(FCPATH.$upload_dir)) {
throw new Exception("It seems that the folder \"".FCPATH.$upload_dir."\" for the field name
\"".$field_name."\" doesn't exists. Please create the folder and try again.");
}
$this->upload_fields[$field_name] = (object) array(
'field_name' => $field_name,
'upload_path' => $upload_dir,
'encrypted_field_name' => $this->_unique_field_name($field_name));
return $this;
}
I'm trying to create a fairly basic CMS for my own site. I attempting to create image form where I can update fields as well as unlink the old image file and attach the new if one is present. When I have a new image uploaded and then go back to the content management page and update either the title or the content of the form my image is unlinked automatically and deleted from the image folder on my local server. Any clue why this might be?
Here is some of the code...
if (isset($_POST["updateArea"])) {
$areaID = $_GET["areaID"];
$area = Web_areas::find_by_id($areaID);
$area->title = $_POST['area_title'];
$area->content = $_POST['area_content'];
if (isset($_FILES['area_upload'])) {
$old_target_path = SITE_ROOT.DS.'public'.DS.$area->image_path();
unlink($old_target_path)
$area->attach_file($_FILES['area_upload']);
$area->update_image();
redirect_to("../public/admin/manage_content.php");
} else {
$area->update();
redirect_to("../public/admin/manage_content.php");
}
}
areaID is PHP being passed through the URL and then I use the static find_by_id to get the information from the database and instantiate it into object attributes that I can then reassign new values and update. Update_image() calls the update() function as well, but it also assigns the image to the directory using move_uploaded_file().
Let me know if you need more information from me to help solving this problem. Thanks!!
Found the problem!! I was using if (isset()) for $_FILE when I should have been using is_uploaded_file(); So the code looks like this now and works great!
if (isset($_POST["updateArea"])) {
$areaID = $_GET["areaID"];
$area = Web_areas::find_by_id($areaID);
$area->title = $_POST['area_title'];
$area->content = $_POST['area_content'];
if (is_uploaded_file($_FILES['area_upload'])) {
$old_target_path = SITE_ROOT.DS.'public'.DS.$area->image_path();
unlink($old_target_path);
$area->attach_file($_FILES['area_upload']);
$area->update_image();
$_SESSION['area_message'] = "Area content and image updated successfully";
redirect_to("../public/admin/manage_content.php");
} else {
$area->update();
$_SESSION['area_message'] = "Area content updated successfully";
redirect_to("../public/admin/manage_content.php");
}
}
I'm using a plugin called jQuery file upload to upload images to a page. Currently it uploads with the original image name as the file name (IMG_1234). I need a specific format for the image name on the server (eg 1.123456.jpg)
I found this PHP code that works for changing the image name:
class CustomUploadHandler extends UploadHandler
{
protected function trim_file_name($name, $type) {
$name = time()."_1";
$name = parent::trim_file_name($name, $type);
return $name;
}
}
When I upload an image, it is named correctly, but the link for the image preview is undefined. This prevents me from deleting the image via the plugin.
The variable data.url is undefined... If I go back to the original code that doesn't rename the image, everything works fine.
Has anyone had any experience with this plugin that could help? Thanks!
EDIT:
I've found part of the problem at least...the function to return the download link (which is also used for deletion) is giving the original file name, not the updated one. I am really new to PHP classes, so I'm not sure where the variable originates and how to fix it. I'd really appreciate any help I can get!
Here's the PHP code for that function:
protected function get_download_url($file_name, $version = null, $direct = false) {
if (!$direct && $this->options['download_via_php']) {
$url = $this->options['script_url']
.$this->get_query_separator($this->options['script_url'])
.'file='.rawurlencode($file_name);
// The `$file_name` variable is the original image name (`IMG_1234`), and not the renamed file.
if ($version) {
$url .= '&version='.rawurlencode($version);
}
return $url.'&download=1';
}
if (empty($version)) {
$version_path = '';
} else {
$version_url = #$this->options['image_versions'][$version]['upload_url'];
if ($version_url) {
return $version_url.$this->get_user_path().rawurlencode($file_name);
}
$version_path = rawurlencode($version).'/';
}
return $this->options['upload_url'].$this->get_user_path()
.$version_path.rawurlencode($file_name);
}
EDIT 2: I think it has something to do with 'param_name' => 'files', in the options. Anyone know what that does?
Fixed it by editing the trim_file_name function inside UploadHandler.php instead of extending the class in index.php.
this might be a bit of a novice question and here is my situation:
i have a upload form for uploading images. and in my editAction i do:
if ($request->isPost()) {
if (isset($_POST['upload_picture']) && $formImageUpload->isValid($_POST)) {
//here i will add the picture name to my database and save the file to the disk.
}
}
$picVal = $this->getmainPic(); // here i do a simple fetch all and get the picture that was just uploaded
$this->view->imagepath = $picVal;
what happens is that the newly uploaded picture doesn't show. I checked the database and the dick and the file is there.
im thinking the problem might be the order of the requests or something similar.
any ideas?
edit: another thing is that in order to make the new image come up i have to do a SHIFT+F5 and not only press the browser refresh button
edit2: more code
i first call the upload to disk function then if that returns success addthe file to the database
$x = $this->uploadToDiskMulty($talentFolderPath, $filename)
if($x == 'success'){
$model->create($data);
}
the upload function
public function uploadToDiskMulty($talentFolderPath, $filename)
{
// create the transfer adapter
// note that setDestiation is deprecated, instead use the Rename filter
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->addFilter('Rename', array(
'target' => $filename,
'overwrite' => true
));
// try to receive one file
if ($adapter->receive($talentFolderPath)) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}
If the picture only appears when you do SHIFT+F5 that means it's a caching problem. Your browser doesn't fetch the image when you upload it. Do you use the same file name?
when using zend add validators for validating a file size and extension.Is it possible to track the file name and size of the file uploaded.Can we get the size and name of the file even when validation fails.I cant track the file name when validation fails as the file not coming to temp directory when validation fails.Is the file validated before storing in temp directory
here is my code snippet:
$document_path_field = $this->CreateElement('file','document_path');
$document_path_field->setLabel('Document');
$document_path_field->setAttrib('class','button');
//$document_path_field->setDestination(SUPPORTING_DOCUMENT_DIRECTORY);
$document_path_field->addValidator('Count', false, 1);
$document_path_field->addPrefixPath('Course_Validate_File', 'Course/validate/File', 'validate');
$document_path_field->addValidator('Size', false, 1000000);
$document_path_field->addPrefixPath('Course_Validate_File', 'Course/validate/File', 'validate');
$document_path_field->addValidator('CheckExtension',false,'docx,doc,jpg,png,gif,pdf');
$document_path_field->clearDecorators();
if(isset($field_required_array['document_path']) && $field_required_array['document_path'] == "Yes")
{
$document_path_field->setRequired(true);
}
else
{
$document_path_field->setRequired(false);
}
$document_path_field->setDecorators($this->setFieldElementDecorators());
if(in_array('document_path',$field_names_array))
{
array_push($form_elements,$document_path_field);
}
$current_document_path = $this->CreateElement('hidden','current_document_path');
$current_document_path->setLabel('Current Document')
->clearDecorators()
->addDecorator($imageviewScript)
->setValue($this->_document_path);
array_push($form_elements,$current_document_path);
The code you have posted looks like it's for a form, not the controller so it doesn't really help tbh.
Under example #2 here: http://framework.zend.com/manual/en/zend.file.transfer.introduction.html#zend.file.transfer.introduction.checking
In the second if statement, you can simply get the file name:
if (!$upload->isValid($file)) {
print "Sorry but $file is not what we wanted";
continue;
} else echo 'File '.$info['name'].' is not allowed';
More info: File Upload using zend framework 1.7.4