ajaxform + file upload + random issues + using <textarea>
Hi,
I've implemented ajaxform with file upload on this site:
https://apply.salk.edu/?eid=a4826f4dd8643e5b5170a9fa60f9229d
(Use 619-222-2222 to get the prefilled data)
I'm having about a 10 in 100 fail rate for the file uploads, but I can't reproduce the problem on any of the browsers. I'm told the progress bar (blockui) just spins and never completes ... and the files sometimes do and sometimes don't upload.
I have been capturing the user-agent strings of these browsers here's a sampling:
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; yie9)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET4.0C; .NET4.0E)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2 Safari/536.26.17
101853 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; MS-RTC LM 8; .NET CLR 2.0.50727; .NET4.0C)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB7.4; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E)
I've attached my full client side and php controller. Here's a snippet of the relevant code:
$j('#upload_form').ajaxForm({ // dataType identifies the expected content type of the server response // dataType: 'text/html', beforeSend: function() { $j.blockUI({ title: 'Salk Application - Uploading Files', theme: true, message: '<h1><img src="/images/ajax-loader.gif" style="vertical-align:bottom;"/>.</h1>' }); }, complete: function(){ $j.unblockUI(); }, ajaxError: function(){ $j.unblockUI(); }, ajaxStop: function(){ $j.unblockUI(); }, success: processUploadResult });
<div id="uploadsTab"> <form action="/upload/staff" method="post" enctype="multipart/form-data" id="upload_form" autocomplete="off"> <table width='100%' id='statusTable'> <tr> <td colspan='3' class='uploadStatus'> <div id="statusMessage"></div> </td> </tr> </table> <table width='100%' id='uploadTable'> <tr> <th class='uploadHeading'> Cover Letter </th> <th class='uploadHeading'> Resume </th> <th class='uploadHeading'> Other File </th> </tr> <tr> <td class='fileFields'> <input type='hidden' id='u_id'> <input name='cover_letter_atch' id='cover_letter_atch' type='file'> </td> <td class='fileFields'> <input name='resume_atch' id='resume_atch' type='file'> </td> <td class='fileFields'> <input name='other_atch' id='other_atch' type='file'> </td> </tr> <tr> <td colspan='3'> <div class="ui-state-highlight ui-corner-all">pdf format is preferred, max file size for each attachment is 2.8MB</div><br><input type="submit" name="submit_upload" id="submit_upload" value="Upload File(s)"> </td> </tr> </table> </form> </div>
- <?php
class UploadController extends Zend_Controller_Action
{
public $uploadFields = array('staff'=>array('resume_atch'=>false,'cover_letter_atch'=>false),
'faculty'=> array('cv_atch'=>true,'research_atch'=>true,'other_atch'=>false));
public function preDispatch()
{
$this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$this->getResponse()
->setHeader('Content-type', 'text/plain')
->setHeader('X-Content-Type-Options', 'nosniff');
}
//upload the file and save the path(s) to the u_id's row in user_info
public function processFilesAndSavePaths($form)
{
$form->getValues();
}
public function renameFile($filename)
{ // safe rename w/timestamp
$timestamp = date('Ymdhis');
return $timestamp."_".(basename(preg_replace("/[^a-zA-Z0-9\.]/", "_", strtolower($filename))));
}
public function uploadHandler($appType)
{
//It seems that ajaxForm doesn't put anything in $_FILES if no file is specified,
//Check for missing required fields
$requiredErrors = false;
$errors = array();
foreach($this->uploadFields[$appType] as $uploadField => $isRequired){
//10-15-2012
if(($_FILES[$uploadField]['size'] == 0) && $isRequired){
//if(!(isset($_FILES[$uploadField])) && $isRequired){
$requiredErrors = true;
$errors[$uploadField] = array('missingRequiredFile'=>'Required');
}
}
if($requiredErrors == true){
echo "<textarea>".json_encode( array('submit_result'=>false,'errors'=>$errors) )."</textarea>";
die();
}
// Use zend transfer to do all of the other validation
//10-15-2012 , only faculty required (and not the other_atch field)
/*if($appType == 'staff' || $uploadField =='other_atch'){
$options = array('ignoreNoFile' => TRUE);
}*/
$options = array('ignoreNoFile' => TRUE);
$upload = new Zend_File_Transfer();
$upload->setOptions($options)->addValidator('Extension', false, 'doc,docx,rtf,txt,pdf');
foreach($this->uploadFields[$appType] as $uploadField=>$isRequired){
if($isRequired == true){
$upload->addValidator('Size',false,array('min'=>1000,'max'=>$this->maxFileSize),$uploadField);
}
else{
//Changed from FilesSize-total sum, to Size
//$upload->addValidator('FilesSize',false,$this->maxFileSize,$uploadField);
}
}
$upload->addValidator('Size',false,$this->maxFileSize);
if (!$upload->isValid()){
$zendErrors = $upload->getMessages();
$errors = array('statusMessage'=>$zendErrors,'inputId'=>$uploadField);
echo "<textarea>".json_encode(array('submit_result'=>false,'errors'=>$errors))."</textarea>";
die;
}
else{ // Good to go, recieve the files
$files = $upload->getFileInfo();
foreach($files as $fieldName => $fileInfo){
// 11/2/2012 prevent empty files from being uploaded (IE sucks)
//print_r($fileInfo);
if($fileInfo['size'] > "400"){
$safeName = $this->renameFile($fileInfo['name']);
$upload->addFilter('Rename', array('target' => APPLICATION_PATH.'/uploads/'.$safeName, 'overwrite' => TRUE), $fieldName);
$upload->receive($fieldName);
$this->saveFileInfo($fieldName, $safeName, $_GET['u_id']);
$this->transferFileToRemoteHost($safeName);
}
}
//respond with true to the view
echo "<textarea>".json_encode(array('submit_result'=>true))."</textarea>";
//set the attachments_upload_complete field in the user_info table
// used to identify records that are cleared for doc conversion
// in the AttachmentConversionController
$this->_helper->SaveApplicantData->setAttachmentsUploadComplete($_GET['u_id']);
}
}