[EXTENSION] FancyUpload

Hey, guys, if anybody has suggestions, found bugs or something about this extension, please, feel free in this topic.

Regards!!

Hi

I am new to this extension…

I hv just changed the url as


  'url'=>$this->createUrl( '/var/www'), 

and run my project. But it shows the failed flag…

Is there any mistake? Pls help me out…

Thanx in advance

hey,

the parameter ‘url’ should point to the controller/action which will manipulate uploaded files, as:

‘url’=>$this->createUrl(‘site/upload’)

where:

site is the SiteController.php which has an action/definition like:

public function actionUpload()

in other words, the ‘url’ parameter points to the server script that receives the files and store them into some folder

the latest version of fancy extension (1.1) includes a folder called code_sample, from where you can copy the code to manipulate files

Be sure you have a folder where you want to store the uploaded files and this folder is writeable by the server. Default parameter in the examples is ‘tmp’ folder, which sould be created under ‘protected’

hope it helps, please let me know if you have any other problems

thanks

:)

regards

Hi

Thank you so much…

It works well…

i didnt set permission for tmp folder…thats the mistake i did… :D

I’m glad that I could help

:)

Regards!!

Thanks for this extension, you clearly put a lot of work into it.

I set up the file, but for some reason the progress bars are not hidden when the page loads so they show all the time. I am using the sample files you posted in the documentation, changing only the url setting:

http://www.socialcollab.com/runtly/dev/image/uploader

I am also not sure how to modify it for a single file implementation that does not contain all these extra buttons (e.g. select files, clear queue, etc.) and information fields? I am looking for an implementation that looks and behaves almost exactly like this:

http://digitarald.de/project/fancyupload/3-0/showcase/single-file-button/

Could you advise how to achieve a similar look and behavior with your extension?

hey, Muhammad, thanks for trying the extension

I’ll take a close look at this problem at night and try to see what’s happening (usually, it happens to me when the file swf is not found, but it doesn’t seem to be this case) and I’m going to check for a way to build the single button upload, maybe some changes in the view parameters or improvement in the extension code

As soon as possible I’ll give feedback

regards

hey, I’ve just released a new fixed version of fancy with the option for the single-button upload

To solve the problem, I changed all javascript calls $( to document.id( , which is the Mootools safe mode for compatibility with other frameworks

Please, download version 1.2 at http://www.yiiframework.com/extension/sfancyupload/ and see the documentation and working samples in the downloaded file

Thanks for reporting

Hope it is useful now

Regards!!!

PS. could you please remove the picture of the car I’ve posted on your website?

http://www.socialcollab.com/runtly/dev/image/uploader

thanks

Hello Scoob.

Just tried your extension. It works very well, thank you!

I have a question, maybe you can help me.

I have a form where the user selects an option that would allow to upload more or less files.

I want to change the limit of uploaded files with javascript when the user changes this option.

Would you happen to know how I can do this?

I’ve posted the same question to the fancyupload support forums.

Thank you.

Hey, thanks for trying that

I’ve got it working by changing a few things in the view fancyqueue:

1 - create html element to store the max limit and put a default value in the option when creating the widget

2 - register javascript functions add() and sub() to add and sub values from max limit input field

3 - register a callback function to update the fileListMax option of fancy -> this is the most important part

In the example below I’ve registered the callback onBrowse, which is called when the user clicks the browse files button. In this callback, we set the option fileListMax to be the value of our html input element. See:




            'onBrowse'=>"function() {

               //up is the internal name given to the object fancy in the extension

               up.setOptions({fileListMax:document.id('lim').get('value')});

            }",



You could also change <input type=“text”> to <input type=“hidden”> if you don’t want the user to see what is the max files limit. Please, take a look at the complete view source below:




<?php


$statusBoxId  = 'fancy-status';

$clearButton  = 'fancy-clear';

$uploadButton = 'fancy-upload';


$this->widget('application.extensions.fancyupload.SFancyQueue',

    array(

        'name'=>'form-fancy',

        'statusBoxId'=>$statusBoxId,            //id for the container div

        'clearButton'=>$clearButton,            //id for "Clear List" link

        'uploadButton'=>$uploadButton,          //id for "Start Upload" link

        'clearButtonLabel'=>'Limpar Lista',     //label for "Clear List" link

        'uploadButtonLabel'=>'Start Upload',    //label for "Start Upload" link

        'targetLabel'=>'Select Files',          //label for "select files" link

        'options'=> array(

                'verbose'=>true,  //remove in production

                'url'=>$this->createUrl('fancy/UploadedFiles'),          //send files to this controller/action

                'multiple'=>true,                                       //multiple files

                'target'=>'fancy-browse',                               //id for "select files" link

                'typeFilter'=>array('Images (jpg, jpeg, gif, png)'=>'*.jpg; *.jpeg; *.gif; *.png','Compressed (zip, rar)'=>'*.zip; *.rar'),   //accept only images and compressed files (better check the mimetype in the controller which receives the file)

                'instantStart'=>false,                                  //do not upload right after the selection of files

                'data'=>array('extradata'=>'your_additional_content'),  //accessible in the controller via $_POST['extradata'] or $_POST['whatever_you_put_in_the_key']

                'fileListMax'=>2,

            ),


            

        'callbacks' => array(

            //'onComplete' => 'function(){alert("Complete");}',

            //'onCancel' => 'function(evt,queueId,fileObj,data){alert("Cancelled");}',


            'onLoad'=>"function() {

                    document.id('$statusBoxId').removeClass('hide');

                    document.id('fancy-fallback').destroy();


                    // We relay the interactions with the overlayed flash to the link

                    this.target.addEvents({

                            click: function() {

                                    return false;

                            },

                            mouseenter: function() {

                                    this.addClass('hover');

                            },

                            mouseleave: function() {

                                    this.removeClass('hover');

                                    this.blur();

                            },

                            mousedown: function() {

                                    this.focus();

                            }

                    });


                    // Interactions for the 2 other buttons


                    document.id('$clearButton').addEvent('click', function() {

                            up.remove(); // remove all files

                            return false;

                    });


                    document.id('$uploadButton').addEvent('click', function() {

                            up.start(); // start upload

                            return false;

                    });

            }",




            'onFail'=> 'function(error) {

                            switch (error) {

                                    case "hidden": // works after enabling the movie and clicking refresh

                                            alert("Para habilitar o sistema de upload, desbloqueie no seu browser e atualize.");

                                            break;

                                    case "blocked": // This no *full* fail, it works after the user clicks the button

                                            alert("Para habilitar o sistema de upload, habilite o filme flash bloqueado");

                                            break;

                                    case "empty": // Oh oh, wrong path

                                            alert("O sistema de upload parece estar faltando, por favor, tente mais tarde");

                                            break;

                                    case "flash": // no flash 9+ <img src='http://www.yiiframework.com/forum/public/style_emoticons/default/sad.gif' class='bbc_emoticon' alt=':(' />

                                            alert("Precisa ter o plugin do Adobe Flash 9 ou superior para usar o upload")

                            }

                    }',


            'onFileSuccess'=> "function(file, response) {

                var json = new Hash(JSON.decode(response, true) || {});


                if (json.get('status') == '1') {

                        file.element.addClass('file-success');

                        file.info.set('html', '<strong>File sent:</strong> (' + json.get('width') + ' x ' + json.get('height') + 'px, <em>' + json.get('mime') + '</em>)');

                } else {

                        file.element.addClass('file-failed');

                        file.info.set('html', '<strong>Error sending:</strong> (' + (json.get('error') ? (json.get('error') + ' #' + json.get('code')) : response));

                }

            }",




            'onSelectFail'=> "function(files) {

                    files.each(function(file) {

                            new Element('li', {

                                    'class': 'validation-error',

                                    html: file.validationErrorMessage || file.validationError,

                                    title: MooTools.lang.get('FancyUpload', 'removeTitle'),

                                    events: {

                                            click: function() {

                                                    this.destroy();

                                            }

                                    }

                            }).inject(this.list, 'top');

                    }, this);

            }",




            /*'onFileComplete'=> "function(file) {

                    up.fileRemove(file);

            }",*/

// ---------------------- callback changed ---------------------

            'onBrowse'=>"function() {

               up.setOptions({fileListMax:document.id('lim').get('value')});

            }",

// ---------------------- callback changed ---------------------


            'onComplete'=>"function() {

               // document.id('fancy-status').setStyle('display','none');

               //up.remove();

               el = document.search('.file-success');

               for (i=0; i<el.length; i++){

                   el[i].destroy();

               }

            }",







//'onBeforeStart'=>"function() {

//var hash = {};

//document.cookie.split(/;\s*/).each(function(cookie) {

//cookie = cookie.split('=');

//if (cookie.length == 2) {

//hash[decodeURIComponent(cookie[0])] = decodeURIComponent(cookie[1]);

//}

//});

//

//up.setOptions({

//data: {cookieName: hash['myfield'], myfield: document.id('myfield').get('value')}

//});

//}",





        )

        

    ));

?>





All the below code was added


limit: <input type="text" value="2" id="lim" name="lim" disabled="true">


<?php


Yii::app()->clientScript->registerScript('lim',

"

function add(){

    //please, perform a check here

    document.id('lim').set('value', document.id('lim').get('value').toInt() + 1);

}




function sub(){

    if(document.id('lim').get('value').toInt() > 1){

        document.id('lim').set('value', document.id('lim').get('value').toInt() -1);

    } else {

        alert('1 file is the lowest value allowed');

    }

}

",

    CClientScript::POS_HEAD

);   ?>


<a href="#" onclick="javascript:add();">add</a>

<a href="#" onclick="javascript:sub();">sub</a>






Hope it helps!!!

Regards!!!

:)

It works great! thanks a lot!

Hey Scoob, Transistor again :)

I’m having a hard time troubleshooting the upload of a single file.

I get:




Failed Upload automovil-t9669.jpg. Please try again. (Error: #400 httpStatus)



This is my widget code:





		<?php $statusBoxId = 'fancy-single';

			$this->widget('application.extensions.fancyupload.SFancySingleButton',

			    array('name'=>'single',

			           'statusBoxId'=>$statusBoxId,

			           'options'=>array(

			                'target'=>'select-0',

			                'queued'=>false,                                //only one file uploaded

			                'multiple'=>false,                              //only select one file

			                'verbose'=>true,                                //remove in production

			                'url'=>$this->createAbsoluteUrl('clientes/upload'),  //send files to this controller/action

			                'typeFilter'=>array('Images (jpg, jpeg, gif, png)'=>'*.jpg; *.jpeg; *.gif; *.png'),  //only images

			                'instantStart'=>true,                           //start upload right after the selecion

			                'appendCookieData'=>true,                       //send cookies together

			            ),

			 

			            'callbacks'=>array(

			                'onSelectSuccess'=>"function(files) {

			                    if (Browser.Platform.linux) window.alert('Warning: Due to a misbehaviour of Adobe Flash Player on Linux,the browser will probably freeze during the upload process. Since you are prepared now, the upload will start right away ...');

			                        this.setEnabled(false);

			                }",

			 

			                'onSelectFail'=>"function(files) {

			                     window.alert(files[0].name + '(Error: #' + files[0].validationError + ')');

			                }",

			 

			                'onQueue'=>"function() {

			                     if (!swf.uploading) return;

			                     var size = Swiff.Uploader.formatUnit(swf.size, 'b');

			                     link.set('html', swf.percentLoaded + '% - ' + size);

			                }",

			 

			                'onFileComplete'=>"function(file) {

			 

			                    if (file.response.error) {

			                        window.alert('Failed Upload ' + this.fileList[0].name + '. Please try again. (Error: #' + this.fileList[0].response.code + ' ' + this.fileList[0].response.error + ')');

			                    } else {

			                        window.alert('Successful Upload');

			                    }

			 

			                    file.remove();

			                    this.setEnabled(true);

			                }",

			 

			                'onComplete'=>"function() {

			                    link.set('html', linkIdle);

			                }",

			            )

			));

		?>



And the Controller action:




<?php

	class UploadAction extends CAction

	{

		public function run(){

			

		    $file = CUploadedFile::getInstanceByName("Filedata");

		 	

		    //this array will be used to send feedback to the uploader

		    $return = array(

		            'status' => '1',

		            'name' => 'nombre'

		            'name' => $file->getName()

		    );

		 

		 

		    /**

		     * ATENTION: this is for demonstration purposes only.

		     * In a real world application, you'd better validate

		     * the files according to your needs

		     */

		    switch(CFileHelper::getMimeType($file->getTempName())){

		       case 'application/zip':

		           break;

		 

		       case 'image/jpeg':

		           $info = @getimagesize($file->getTempName());

		            if ($info) {

		                $return['width']  = $info[0];

		                $return['height'] = $info[1];

		                $return['mime']   = $info['mime'];

		            }

		           break;

		 

		       default:

		            $return = array(

		                'status' => '0',

		                'error' => 'Tipo de arquivo não permitido'

		            );

		           //here you could put some code to forget about the file, once it is not allowed

		    }

		 

		    //save the file

		    $file->saveAs(Yii::app()->getBasePath().'/tmp/'.$file->getName());

		 

		    /*send some feedback to the page. Can be processed by the function onFileSuccess. See in the Queue view code how to get the values. You can send any value to the view using the $return array. In the view, you just need to invoke json.get('key') method*/

		    echo json_encode($return);

		 

		}

	}

?>



As you can see, it’s pretty much the same code you have in your documentation.

But I can’t find a way to debug this error, I can’t find anything that helps in Firebug.

What can I do?

Thank you.

hey, this error means that there may be something wrong in the path

‘url’=>$this->createAbsoluteUrl(‘clientes/upload’) //in your view code

or you don’t have writing permission to the directory you’re trying to save the files:

$file->saveAs(Yii::app()->getBasePath().’/tmp/’.$file->getName()); //in the controller code

please, be sure you have created the directory /protected/tmp/ with permission 777 (Linux) or everyone full control (windows)

and the action “upload” exists in your controller “clientes”, as you give the path in the ‘url’ parameter

and also, if you are using rbac access control filter in your "clientes" controller, try bypassing the action "upload"

to find out what’s wrong, I’d suggest the following steps:

1 - change the code of your action upload to be simply




echo "my action was called";



2 - try to access http://path/to/your/application/clientes/upload or http://path/to/your/application/index.prp?r=clientes/upload

This way we’ll certify that the action upload in the controller clientes is called. If the output is the message you’re calling so go to step 3

3 - create the /protected/tmp directory and make it writeable

4 - put back the code to save files in your action, it would be something simply like:




$file = CUploadedFile::getInstanceByName("Filedata");

$file->saveAs(Yii::app()->getBasePath().'/tmp/'.$file->getName());



5 - try to upload the file and see if it is saved in /protected/tmp

I’ve ran into a similar problem and in my case it was the permission to the action /mycontroller/myUploadAction

Please, let me know what happens after trying these suggestions. Thanks

Regards

:)

Hey Scoob, thanks for replying so fast and detailed.

I tried steps 1 and 2 (making sure the action is called) and it works.

Then checked step 3 (making sure the tmp directory exists and it is writable).

Then step 4, but I still get a 400 error.

I tried this too, in my action, I wrote this:




	public function actionUpload()

	{

		$return = array(

			'status' => '1',

			'name' => 'some name'

		);

	       echo json_encode($return);

	       //$file = CUploadedFile::getInstanceByName("Filedata");

	       //$file->saveAs(Yii::app()->getBasePath().'/tmp/'.$file->getName());

	}



When accessed directly I get the JSON on the screen ok.

When I upload a file, I still get a 400 error.

hum…weird …just for curious…i’m testing it in Yii 1.0.9 …what’s your Yii version? please, let me know and test to see what happens when we use exactly the same code and the same Yii version

I’d suggest that you do a check in your .htaccess file too (if running on Linux). I also noticed that some callbacks in the posts we’ve wrote are not in camelCase like “onselectFail” (should be “on Select Fail”) (forum bug?)

In order to perform a sync test, could you please do a copy/paste of the entire code below and check if it also works in your server? (around here, with Yii 1.0.9 / Linux and uploading a jpg file it worked fine)

in SiteController:




<?php


class SiteController extends CController

{


    public $defaultAction='index';


	/**

	 * This is the default 'index' action that is invoked

	 * when an action is not explicitly requested by users.

	 */

	public function actionIndex()

	{

            $this->render('index');

	}




    public function actionUploadedFiles(){


        $file  = CUploadedFile::getInstanceByName("Filedata");


        if ($file->size > 0) {


            switch(CFileHelper::getMimeType($file->getTempName())){


                case 'image/jpeg':


                    //returning to the widget fancy

                    $return = array(

                        'status' => '1',

                        'name' => $file->getName()

                    );


                    //save the temporary file

                    $targetFile = Yii::app()->getBasePath().'/tmp/'. $file->getName();

                    $file->saveAs($targetFile);


                    break;


                default:

                    $return = array(

                        'status' => '0',

                        'name' => 'Tipo de arquivo não permitido'

                    );




            }


            echo json_encode($return);


        }

    }


}



the index view, inside /protected/views/site




<?php $statusBoxId = 'fancy-single' ?>


<?php $this->widget('application.extensions.fancyupload.SFancySingleButton',

    array('name'=>'single',

           'statusBoxId'=>$statusBoxId,

           'targetLabel'=>'Trocar Imagem',

           'options'=>array(

                'target'=>'select-0',

                'queued'=>false,                                //only one file uploaded

                'multiple'=>false,                              //only select one file

                'verbose'=>true,                                //remove in production

                'url'=>$this->createUrl('site/UploadedFiles'),  //send files to this controller/action

                'typeFilter'=>array('Fotos (jpg)'=>'*.jpg;'),  //only images

                'instantStart'=>true,                           //start upload right after the selecion

                'appendCookieData'=>true,                       //send cookies together

            ),




            'callbacks'=>array(

                'onSelectSuccess'=>"function(files) {

                        this.setEnabled(false);

                }",


                'onSelectFail'=>"function(files) {

                     window.alert(files[0].name + '(Erro: #' + files[0].validationError + ')');

                }",




                'onQueue'=>"function() {

                     if (!swf.uploading) return;

                     var size = Swiff.Uploader.formatUnit(swf.size, 'b');

                     link.set('html', swf.percentLoaded + '% - ' + size);

                }",


                'onLoad'=>"function() {

                    document.id('$statusBoxId').setStyle('background-image','url('+ document.id('imageurl').get('value')  +')');

                    document.id('$statusBoxId').setStyle('width','250px');

                    document.id('$statusBoxId').setStyle('height','250px');

                }",





                'onFileComplete'=>"function(file) {


                    if (file.response.error) {

                        window.alert('Upload Falhou ' + this.fileList[0].name + '. Tente novamente. (Erro: #' + this.fileList[0].response.code + ' ' + this.fileList[0].response.error + ')');

                    } else {

                        window.alert('Success!');

                        location.reload();

                    }


                    file.remove();

                    this.setEnabled(true);

                }",


                'onComplete'=>"function() {

                    link.set('html', linkIdle);

                }",


            )




)); ?>




lets see what we get now

:)

The two files are attached to avoid camel case forum bug

Do you think it could be the Yii version?

I am using 1.1 for this particular project.

Let me try what you say in another project that is running with 1.0.9

Thank you!

Well… no luck.

I tried this on a new, fresh project. Even downloaded fancyupload extension again.

This time I always get a Success message, but the file is not uploaded.

I’ve found out why this happens, CUploadedFile::getInstanceByName returns empty.

However, if I output print_r($_FILES), the file is there, but with a catch, the [type] is application/octet-stream

How weird is that?

I can continue with $_FILES from here, but I am curious why CUploadedFile is not working.

It seems that the 400 error happens only with 1.1

What do you think?

I’ve just created a fresh instalation the same way with 1.1dev and got Success message but no files in tmp. Maybe some Yii guy could help us. Looking at CUploadedFile.php class I noticed that the class was changed completely. I’ll take a look deeply before posting something to Yii guys.

Thanks for your patience and your help!

:)

hey, transistor, I’ve made some progress around here.

I did a long and exaustive test with every single line of code in both my controller and view

The first thing I changed:




switch(CFileHelper::getMimeType($file->getTempName()))



Should be




switch(CFileHelper::getMimeType($file->getName()))



Otherwise, getMimeType will return null and the file will never be saved

The second thing:

a better way to know what is happening is to save a log file like:




$logFile = Yii::app()->getBasePath().'/tmp/uplog.txt';


$result = array();

$result['time'] = date('r');

$result['temp'] = $file->getTempName();

$result['name'] = $file->getName();

$result['addr'] = substr_replace(gethostbyaddr($_SERVER['REMOTE_ADDR']), '******', 0, 6);

$result['agent'] = $_SERVER['HTTP_USER_AGENT'];

$result['type']  = $file->getType();

$result['mimename'] = CFileHelper::getMimeType($file->getName());


$log = @fopen($logFile, 'a');

if ($log) {

	fputs($log, print_r($result, true) . "\n---\n");

	fclose($log);

}



I’ve tested the following code in my hosting service with some combinations:

  • a chmoded 777 tmp directory

  • a /images/anotherdir/ with chmod 755, group owner = my ftp user and owner my ftp user

  • with a .htaccess file inside the target directory following a tip found in fancy’s official website:

    From the swfupload documentation (it applies to all Flash scripts depending on FileReference):

    If you are using Apache with mod_security this will not work, you need to put the following in your .htaccess file to disable mod_security:

SecFilterEngine Off

SecFilterScanPOST Off

Disabling mod_security isn’t allowed on some shared hosts, and only do this if you know what you are doing. This is due to a bug in the way that flash sends the headers back to the server according to the Flash 8 documentation
  • without .htaccess file inside the target directory

Results:

  • the tip .htaccess doesn’t seem to be suitable in my case

  • chmoded 777 dir was not really necessary, just the 755 with owner = my ftp user in the hosting service

  • switch(CFileHelper::getMimeType($file->getName())) made a huge difference

  • log files are awsome :)

Codes to the view and controller following attached (maybe you’ll need to adjust some parts of controller)

All things working fine now, please, log everything you want to the logfile and let me know if your image file is uploaded correctly with these changes.

Regards! :)

Scoob.

Thanks a lot! Great detective work there ;)

It works with Yii 1.0.9 but with 1.1 I am still getting Error 400.