2010-04-28 132 views
3

希望这里有人可能对我的问题有一个答案。

我有一个基本的表单,包含简单的字段,如姓名,号码,电子邮件地址等和1个文件上传字段。

我想添加一些验证到我的脚本,检测文件是否过大,然后拒绝用户回到窗体选择/上传一个较小的文件。

我的问题是,如果用户选择的文件大于我的验证文件大小规则并且大于php.ini POST_MAX_SIZE/UPLOAD_MAX_FILESIZE并推送提交,那么PHP似乎会尝试处理该表单,但仅在POST_MAX_SIZE上失败设置,然后清除整个$ _POST数组,并不返回任何形式。

有没有办法解决这个问题?当然,如果有人上传超过php.ini中配置的最大大小的东西,那么你仍然可以获得$ _POST数据的其余部分?

这是我的代码。

<?php 

    function validEmail($email) 
    { 
     $isValid = true; 
     $atIndex = strrpos($email, "@"); 
     if (is_bool($atIndex) && !$atIndex) 
     { 
      $isValid = false; 
     } else { 
      $domain = substr($email, $atIndex+1); 
      $local = substr($email, 0, $atIndex); 
      $localLen = strlen($local); 
      $domainLen = strlen($domain); 

      if ($localLen < 1 || $localLen > 64) 
      { 
      // local part length exceeded 
      $isValid = false; 
      } 
      else if ($domainLen < 1 || $domainLen > 255) 
      { 
      // domain part length exceeded 
      $isValid = false; 
      } 
      else if ($local[0] == '.' || $local[$localLen-1] == '.') 
      { 
      // local part starts or ends with '.' 
      $isValid = false; 
      } 
      else if (preg_match('/\\.\\./', $local)) 
      { 
      // local part has two consecutive dots 
      $isValid = false; 
      } 
      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) 
      { 
      // character not valid in domain part 
      $isValid = false; 
      } 
      else if (preg_match('/\\.\\./', $domain)) 
      { 
      // domain part has two consecutive dots 
      $isValid = false; 
      } 
      else if 
      (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local))) 
      { 
      // character not valid in local part unless 
      // local part is quoted 
      if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))) 
      { 
       $isValid = false; 
      } 
      } 

     } 
     return $isValid; 
    } 

     //setup post variables 
     @$name = htmlspecialchars(trim($_REQUEST['name'])); 
     @$emailCheck = htmlspecialchars(trim($_REQUEST['email'])); 
     @$organisation = htmlspecialchars(trim($_REQUEST['organisation'])); 
     @$title = htmlspecialchars(trim($_REQUEST['title'])); 
     @$phone = htmlspecialchars(trim($_REQUEST['phone'])); 
     @$location = htmlspecialchars(trim($_REQUEST['location'])); 
     @$description = htmlspecialchars(trim($_REQUEST['description'])); 
     @$fileError = 0; 
     @$phoneError = ""; 

     //setup file upload handler 
     $target_path = 'uploads/'; 
     $filename = basename(@$_FILES['uploadedfile']['name']); 
     $max_size = 8000000; // maximum file size (8mb in bytes) NB: php.ini max filesize upload is 10MB on test environment. 
     $allowed_filetypes = Array(".pdf", ".doc", ".zip", ".txt", ".xls", ".docx", ".csv", ".rtf"); //put extensions in here that should be uploaded only. 
     $ext = substr($filename, strpos($filename,'.'), strlen($filename)-1); // Get the extension from the filename. 

     if(!is_writable($target_path)) die('You cannot upload to the specified directory, please CHMOD it to 777.'); //Check if we can upload to the specified upload folder. 


     //display form function 
     function displayForm($name, $emailCheck, $organisation, $phone, $title, $location, $description, $phoneError, $allowed_filetypes, $ext, $filename, $fileError) 
     { 
      //make $emailCheck global so function can get value from global scope. 
      global $emailCheck; 
      global $max_size; 



      echo '<form action="geodetic_form.php" method="post" name="contact" id="contact" enctype="multipart/form-data">'."\n". 
       '<fieldset>'."\n".'<div>'."\n"; 

      //name   
      echo '<label for="name"><span class="mandatory">*</span>Your name:</label>'."\n". 
       '<input type="text" name="name" id="name" class="inputText required" value="'. $name .'" />'."\n"; 

       //check if name field is filled out 
       if (isset($_REQUEST['submit']) && empty($name)) 
       {   
        echo '<label for="name" class="error">Please enter your name.</label>'."\n"; 
       } 

      echo '</div>'."\n". '<div>'."\n"; 

      //Email  
      echo '<label for="email"><span class="mandatory">*</span>Your email:</label>'."\n". 
       '<input type="text" name="email" id="email" class="inputText required email" value="'. $emailCheck .'" />'."\n"; 

       // check if email field is filled out and proper format 
       if (isset($_REQUEST['submit']) && validEmail($emailCheck) == false) 
       { 
        echo '<label for="email" class="error">Invalid email address entered.</label>'."\n"; 
       } 

      echo '</div>'."\n". '<div>'."\n"; 

      //organisation  
      echo '<label for="phone">Organisation:</label>'."\n". 
       '<input type="text" name="organisation" id="organisation" class="inputText" value="'. $organisation .'" />'."\n"; 
      echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n"; 

      //title  
      echo '<label for="phone">Title:</label>'."\n". 
       '<input type="text" name="title" id="title" class="inputText" value="'. $title .'" />'."\n";   
      echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n"; 

      //phone  
      echo '<label for="phone"><span class="mandatory">*</span>Phone <br /><span class="small">(include area code)</span>:</label>'."\n". 
       '<input type="text" name="phone" id="phone" class="inputText required" value="'. $phone .'" />'."\n";  

      // check if phone field is filled out that it has numbers and not characters 
      if (isset($_REQUEST['submit']) && $phoneError == "true" && empty($phone)) echo '<label for="email" class="error">Please enter a valid phone number.</label>'."\n";  

      echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n"; 

      //Location  
      echo '<label class="location" for="location"><span class="mandatory">*</span>Location:</label>'."\n". 
       '<textarea name="location" id="location" class="required">'. $location .'</textarea>'."\n"; 

      //check if message field is filled out 
      if (isset($_REQUEST['submit']) && empty($_REQUEST['location'])) echo '<label for="location" class="error">This field is required.</label>'."\n"; 

      echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n"; 

      //description  
      echo '<label class="description" for="description">Description:</label>'."\n". 
       '<textarea name="description" id="queryComments">'. $description .'</textarea>'."\n";    
      echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n"; 

      //file upload 
      echo '<label class="uploadedfile" for="uploadedfile">File:</label>'."\n". 
       '<input type="file" name="uploadedfile" id="uploadedfile" value="'. $filename .'" />'."\n"; 

      // Check if the filetype is allowed, if not DIE and inform the user. 
      switch ($fileError) 
      { 
      case "1": 
       echo '<label for="uploadedfile" class="error">The file you attempted to upload is not allowed.</label>'; 
      break; 

      case "2": 
       echo '<label for="uploadedfile" class="error">The file you attempted to upload is too large.</label>'; 
      break; 
      } 
      echo '</div>'."\n". '</fieldset>'; 

      //end of form 
      echo '<div class="submit"><input type="submit" name="submit" value="Submit" id="submit" /></div>'. 
       '<div class="clear"><p><br /></p></div>'; 
     } //end function 

     //setup error validations 
     if (isset($_REQUEST['submit']) && !empty($_REQUEST['phone']) && !is_numeric($_REQUEST['phone'])) $phoneError = "true"; 
     if (isset($_REQUEST['submit']) && $_FILES['uploadedfile']['error'] != 4 && !in_array($ext, $allowed_filetypes)) $fileError = 1; 
     if (isset($_REQUEST['submit']) && $_FILES["uploadedfile"]["size"] > $max_size) $fileError = 2; echo "this condition " . $fileError; 

     $POST_MAX_SIZE = ini_get('post_max_size'); 
     $mul = substr($POST_MAX_SIZE, -1); 

     $mul = ($mul == 'M' ? 1048576 : ($mul == 'K' ? 1024 : ($mul == 'G' ? 1073741824 : 1))); 
     if ($_SERVER['CONTENT_LENGTH'] > $mul*(int)$POST_MAX_SIZE && $POST_MAX_SIZE) echo "too big!!"; 
     echo $POST_MAX_SIZE; 


     if(empty($name) || empty($phone) || empty($location) || validEmail($emailCheck) == false || $phoneError == "true" || $fileError != 0) 
     { 
      displayForm($name, $emailCheck, $organisation, $phone, $title, $location, $description, $phoneError, $allowed_filetypes, $ext, $filename, $fileError); 
      echo $fileError; 
      echo "max size is: " .$max_size; 
      echo "and file size is: " . $_FILES["uploadedfile"]["size"]; 
      exit; 
     } else { 

      //copy file from temp to upload directory 
      $path_of_uploaded_file = $target_path . $filename; 
      $tmp_path = $_FILES["uploadedfile"]["tmp_name"]; 
      echo $tmp_path; 
      echo "and file size is: " . filesize($_FILES["uploadedfile"]["tmp_name"]); 
      exit; 
      if(is_uploaded_file($tmp_path)) 
      { 
       if(!copy($tmp_path,$path_of_uploaded_file)) 
       { 
       echo 'error while copying the uploaded file'; 
       } 
      } 

     //test debug stuff 
      echo "sending email..."; 
      exit; 


     } 
     ?> 

PHP在日志中返回此错误: [29-APR-2010 10时32分47秒] PHP警告:57885895个字节POST内容长度超过在线0的在未知10485760个字节的限制

借口所有调试东西:)

FTR,我在IIS上运行PHP 5.1.2。

+1

这听起来并不正确,所有的POST变量应该保持不变。您可能必须发布该代码。 – 2010-04-28 21:30:31

+0

现在只需将其添加到原始帖子。 – Jared 2010-04-28 21:38:35

+0

@Jared:应该在我的第一条评论中提及,但是您可能还想查看http://www.php.net/manual/en/features.file-upload.common-pitfalls.php – 2010-04-28 21:53:57

回答

7

PHP抛出所有的POST数据了,因为没有空间放它。只有部分数据没有可靠性。

我会在单独的步骤中以不同的形式上传必要的文件来解决此问题。您可以存储会话中已获取的值,确保它们不会因为过多的POST数据而丢失。

+0

我开始认为这是唯一的方法:(感谢所有的提示/解决方案的人欣赏它 – Jared 2010-04-29 21:41:46

+0

如果有人遇到这个很好的有用的问题......我最终做的是分开文件上传从主窗体开始,构建了一个多阶段表单,因此当用户获得文件上传并且文件大于POST_MAXSIZE时,在表单详细信息被保存到会话中时是否清除了标题并不重要,我使用'if'($ _ SERVER ['REQUEST_METHOD'] =='POST'&& empty($ _ POST)&& $ _SERVER ['CONTENT_LENGTH']> 0)'检测标头是否已满 – Jared 2011-02-03 21:12:05

1

当您发现_POST数组已被删除后,您可能会尝试查看是否可以从php://inputphp://stdin中读取任何内容。您可能能够检索从那里POST数据和手工处理,但手工also says,这不会对//input工作,如果你的表格是使用enctype=multipart/form-data

+0

我给了你一个聪明点子的投票。但是,这不会与enctype = multipart/form-data一起使用,而不是我正在寻找的答案。虽然谢谢! 我不能相信这么简单的事情需要一个复杂的解决方案。为什么PHP会清除$ _POST数组呢?我猜是因为头文件从大文件上传完整? – Jared 2010-04-29 02:48:35

+0

那么,PHP会按照它们从客户端发送的顺序来处理表单字段。如果文件字段是表单中的第一项,并且文件超出了大小限制,则在处理任何其他字段之前,处理将中止。尝试将文件字段移动到表单底部,看看会发生什么。 – 2010-04-29 13:54:29

3

Erisco是对的,这需要分解成多个步骤。然而,我不相信有必要向用户公开此后端描述,因此我建议采取以下其中一种措施:

将文件上传分解为单独的<form>元素。当提交采取行动或者形式,取消默认的动作,而是做的两两件事之一:

  1. 通过AJAX提交的常规形式的数据,那就是完成时通过标准提交上传的文件过程(涉及页面重新加载和什么不)
  2. 检出this example of iFrame trickery上传文件,确保它不是太大,并防止该页面甚至不会通过重新加载。如果文件通过,请将其标识符存储在隐藏的输入元素中,并正常提交表单。如果文件没有正确上传,请采取适当的措施。请注意,这个解决方案不需要你使用PHP会话,只需要一点回应就可以了。
+0

我同意在可能的情况下使用JavaScript,以缓解用户的烦恼。 – erisco 2010-04-29 18:15:41

0

“尝试将文件移动领域的 底部形态,看看会发生 - 马克·B中。”

不幸的是,同样的情况:在$_POST阵列被清除。 所以iFrame的诡计似乎是最好的解决方案之一。谢谢你,Dereleased

0

的招数之一就是用这样的:

$lE = error_get_last(); 
if ( !empty($lE) && strpos($lE['message'] , 'POST Content-Length') !== false) 
{ 
die ('Naughty naughty. you can only upload xxxxx bytes'); 
} 
相关问题