我目前正在使用symfony 1.4,并希望允许用户上传Microsoft Word docx文件。 使用用户下面的sfWidgetFormInputFile小部件和sfValidatorFile,可以使用简单的Web表单来select并成功上传他们的docx文件。
$this->widgetSchema['file_name'] = new sfWidgetFormInputFile(array('label' => 'File')); $this->validatorSchema['file_name'] = new sfValidatorFile(array( 'required' => true, 'path' => sfConfig::get('sf_upload_dir').DIRECTORY_SEPARATOR.sfConfig::get('app_dir_file_sharing').DIRECTORY_SEPARATOR, 'mime_types' => array('application/msword', 'application/vnd.ms-word', 'application/msword', 'application/msword; charset=binary') ), array( 'invalid' => 'Invalid file.', 'required' => 'Select a file to upload.', 'mime_types' => 'The file must be a supported type.' ));
问题是,file upload后,扩展名改为.zip文件包含xml文件的文件树。 我的理解是,这是因为Office 2007现在使用Open xml文件格式。 有什么办法可以防止这种情况发生使用symfony或PHP?
问题是内容嗅探。 新的Office格式是.zip文件,如果上传时,内容被嗅探,浏览器会将其识别为ZIP文件,并设置Content-Type标头。 同样,除非您的服务器设置了正确的Content-Type HTTP响应头,否则在下载时,浏览器会认为这是一个ZIP文件。
Symfony 1.3+为sfValidatorFile提供了一个mime_type_guessers
选项,它允许你定义你自己的mime类型的猜测PHP可调用或者使用猜测中的构建。 调用3个内置的mime类型的猜测者可以找到docx的正确的文件类型,并保持docx文件的扩展名。
这里是使用guessFromFileinfo更新的代码:
$this->validatorSchema['file_name'] = new sfValidatorFile(array( 'required' => true, 'path' => sfConfig::get('sf_upload_dir').DIRECTORY_SEPARATOR.sfConfig::get('app_dir_file_sharing').DIRECTORY_SEPARATOR, 'mime_type_guessers' => array('guessFromFileinfo'), 'mime_types' => array('application/msword', 'application/vnd.ms-word', 'application/msword', 'application/msword; charset=binary') ), array( 'invalid' => 'Invalid file.', 'required' => 'Select a file to upload.', 'mime_types' => 'The file must be a supported type.' ));
这似乎是Symfony的文件类型检测中的一个错误 。 描述解决方法。
建议使用mime_type_guessers
使用一个不存在的函数。 如果你想使用sfValidatorFile方法,你应该写array(array('sfValidatorFile', 'guessFromFileinfo'))
。 建议的解决方案根本不使用MIME类型的检测,并导致我的系统上的传统Excel格式的问题。
我通过扩展sfValidatorFile类和更改getMimeType方法解决了这个问题。
在lib文件夹中创建一个新的msValidatorFile.class.php文件:
<?php class msValidatorFile extends sfValidatorFile { protected function getMimeType($file, $fallback) { $arrayZips = array( "application/zip", "application/x-zip", "application/x-zip-compressed"); $officeTypes = array( "application/vnd.ms-word.document.macroEnabled.12", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "application/vnd.ms-powerpoint.template.macroEnabled.12", "application/vnd.openxmlformats-officedocument.presentationml.template", "application/vnd.ms-powerpoint.addin.macroEnabled.12", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.ms-excel.addin.macroEnabled.12", "application/vnd.ms-excel.sheet.binary.macroEnabled.12", "application/vnd.ms-excel.sheet.macroEnabled.12", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel.template.macroEnabled.12", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"); foreach ($this->getOption('mime_type_guessers') as $method) { $type = call_user_func($method, $file); if (null !== $type && $type !== false) { if (in_array($type, $arrayZips) && in_array($fallback, $officeTypes)) { return $fallback; } return strtolower($type); } } return strtolower($fallback); } }
在表单代码中使用这个新的验证器:
$this->validatorSchema['file'] = new msValidatorFile(array('required' => false, 'path' => sfConfig::get('sf_upload_dir') ));