Няколко полета за качване на файлове на една форма

vinsbg

Registered
Здравейте,

Имам следната елементарна форма:
Код:
<form class="form-horizontal" name="form-horizontal" action="" method="post" role="form" enctype="multipart/form-data" >					 
     <div class="form-group">
	   <label class="control-label col-sm-2" for="upload_plan">Plan: </label>
		<div class="col-sm-10">
	         	<input type="file" class="form-control add1" name="file[]" id="upload_plan" multiple>
		 </div>
     </div> 
</form>
И php часта към нея
Код:
  $permitted = array('application/vnd.ms-excel', 'application/pdf', 'application/msword', 'image/gif', 'image/jpeg', 'image/jpg', 'image/png', 'image/bmp'
  ,'application/msword', 'application/mspowerpoint', 'application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 
  'application/x-mspowerpoint', 'application/mspowerpoint', 'application/x-compressed', 'application/x-zip-compressed', 'application/zip');
  if (count($_FILES["file"]) > 0) {
  
    $folderName = "uploads/";

    $sql = "INSERT INTO document_upload ( upload_plan, upload_size, upload_type, document_path) 
				  	VALUES ( :upload_plan,  :upload_size, :upload_type, :document_path)";
    $stmt = $pdo->prepare($sql);
     for ($i = 0; $i < count($_FILES["file"]["name"]); $i++) {

      if ($_FILES["file"]["name"][$i] <> "") {     
        if ($permitted) {
  
          $fileSize = $_FILES['file']['size'][$i];
          $fileType = $_FILES['file']['type'][$i];
          $fileName = $_FILES['file']['name'][$i];
          $tmpName  = $_FILES['file']['tmp_name'][$i];
          
	  $ext = substr(strrchr($fileName, "."), 1);
	  $randName = rand(10000, 990000) . '-' .$fileName;
          $filepath = $folderName . $randName;
       
          if (!move_uploaded_file($tmpName, $filepath)) {
            $emsg .= "Error while uploadinf file - <strong>" . $_FILES["file"]["name"][$i] . "</strong>. Please try again. <br>";
          } else {
            $smsg .= "The file <strong>" . $_FILES["file"]["name"][$i] . "</strong> is added successfully. <br>";
            /*             * ****** insert into database starts ******** */
           			         
            try {
              $stmt->bindValue(":upload_plan", $randName, PDO::PARAM_STR);                           
              $stmt->bindValue(":upload_size", $fileSize, PDO::PARAM_STR);
              $stmt->bindValue(":upload_type", $fileType, PDO::PARAM_STR); 
              $stmt->bindValue(":document_path", $filepath, PDO::PARAM_STR);  
                                                                                                                                                      

              $stmt->execute();
              $result = $stmt->rowCount();
              if ($result > 0) {
                // file uplaoded successfully.
              } else {
                // failed to insert into database.
              }
            } catch (Exception $ex) {
              $emsg .= "<strong>" . $ex->getMessage() . "</strong>. <br>";
            }
          }
        } else {
          $emsg .= "This file <strong>" . $_FILES["file"]["name"][$i] . "</strong> isn't permitted. <br>";
        }
      }
    }
    $msg .= (strlen($smsg) > 0) ? successMessage($smsg) : "";
    $msg .= (strlen($emsg) > 0) ? errorMessage($emsg) : "";
  } else {
    $msg = errorMessage("You must add at least one file.");
  }
Въпроса ми е как да добавя още 2 полета за качване на файлове? Т.е. да добавя това към формата
Код:
<div class="form-group">
	<label class="control-label col-sm-2" for="upload_plan_2">Plan_2: <br><small style="color: red;">( pdf only )</small></label>
	<div class="col-sm-10">
	         <input type="file" class="form-control add" name="file[]" id="upload_plan_2" multiple>
	</div>						
</div>	
<div class="form-group">
	<label class="control-label col-sm-2" for="upload_materials">Materials: <br><small style="color: red;">( doc, ppt, pdf, xls, video or image )</small></label>
		<div class="col-sm-10">
    	  	        <input type="file" class="form-control add" name="file[]" id="upload_materials" multiple>
		</div>						
</div>
Нужно е да са 3 различни полета... иначе с едно поле ми е ясно как става, но с 3... Как в PHP часта да го направя? В базата съм добавил още 2 полета upload_plan_2 и upload_materials
 
Добавяш допълните input полета и им даваш сътоветно различни имена и не добавяш multiple атрибута.

<div class="form-group">
<label class="control-label col-sm-2" for="upload_plan">Plan: </label>
<div class="col-sm-10">
<input type="file" class="form-control add1" name="upload_plan" id="upload_plan">
</div>
</div>

И след това може да достъпиш този файл от $_FILES променливата. Ще е с ключ upload_plan (както е name на input-a).

Код:
$_FILES['upload_plan']

След това си го качваш, по същия начин, както качваш всеки един файл от вече съществуващия ти input и го записваш в DB.

А иначе имаш форма с input, който има име file[]. Двете квадратни скоби в края на името означава, че PHP ще го приеме като масив. Ако имаш атрибута multiple, браузъра ще отвори multiple select прозорец и ще прати файловете в този масив.

За да направиш single file upload, добавяш ново поле (input) и в PHP-то го намираш по това име.
Имената са уникални. Ако например имаш 2 полета:
Код:
<input type="text" name="myText[]" />
<input type="text" name="myText[]" />

И след това в PHP напишеш:
Код:
var_dump($_POST['myText']);

Резултата ще е масив с 2 елемента и всеки елемент ще е стринг с това, което е било вкарано в тези два инпута.

Но ако направиш:

Код:
<input type="text" name="myText" />
<input type="text" name="myText" />

и после изпринтиш резултата в PHP-то, $_POST['myText'] ще е само текста, който е бил вкаран в последното поле с име myText. Защото при изпращането на формата в $_POST се добавя ключ myText и се присвоява стойността на първото поле. След това се обработва и следващото поле, което директно презаписва предната стойност, тъй като ключовете в масивите в PHP са уникални.
 
Т.е. ако правилно съм разбрал за всяко поле ще имам :
Код:
//file 1
	          $fileSize = $_FILES['file']['size'][$i];
	          $fileType = $_FILES['file']['type'][$i];
	          $fileName = $_FILES['file']['name'][$i];
	          $tmpName  = $_FILES['file']['tmp_name'][$i];
	          
		  $ext = substr(strrchr($fileName, "."), 1);
		  $randName = rand(10000, 990000) . '-' .$fileName;
	          $filepath = $folderName . $randName;
//file 2
	          $fileSize2 = $_FILES['file2']['size'][$i];
	          $fileType2 = $_FILES['file2']['type'][$i];
	          $fileName2 = $_FILES['file2']['name'][$i];
	          $tmpName2  = $_FILES['file2']['tmp_name'][$i];
	          
		  $ext = substr(strrchr($fileName2, "."), 1);
		  $randName2 = rand(10000, 990000) . '-' .$fileName2;
	          $filepath2 = $folderName2 . $randName2;
//file 3
	          $fileSize3 = $_FILES['file3']['size'][$i];
	          $fileType3 = $_FILES['file3']['type'][$i];
	          $fileName3 = $_FILES['file3']['name'][$i];
	          $tmpName3  = $_FILES['file3']['tmp_name'][$i];
	          
		  $ext = substr(strrchr($fileName3, "."), 1);
		  $randName3 = rand(10000, 990000) . '-' .$fileName3;
	          $filepath3 = $folderName3 . $randName3;
Това така ли е? И съответно ако е така трябва ли в базата да добавя по още 2 полета за всеки файл, където да записва filetype и filesize?
 
Дам, може да си направиш една функция, която да "обобщи" действията, които ти се повтарят.

В базата данни може да ги записваш, както ти е най-удобно.
 
Fakeheal каза:
Дам, може да си направиш една функция, която да "обобщи" действията, които ти се повтарят.

В базата данни може да ги записваш, както ти е най-удобно.
Но ако не направя в базата нови полета за файлтайпа и файлсайза няма ли да ги презаписва едно върху друго?
 
vinsbg каза:
Fakeheal каза:
Дам, може да си направиш една функция, която да "обобщи" действията, които ти се повтарят.

В базата данни може да ги записваш, както ти е най-удобно.
Но ако не направя в базата нови полета за файлтайпа и файлсайза няма ли да ги презаписва едно върху друго?

Защо ти е да ги записваш?

Aко имаш файла, другите могат да се изведат от него.
 
Ето ти функция за да не пишеш за всяко поле един и същ код + няма да ти се налага да променяш php-то, ако решиш да добавяш още полета:
PHP:
foreach (array_keys($_FILES) as $file) {
    for ($i = 0; $i < count($_FILES[$file]['name']); $i++) {
        //$file - името на input-а, към който е прикачен файла
        echo $file . ' - ' . $_FILES[$file]['name'][$i] . '<br>';
    }
}
 
SVTerziev каза:
Ето ти функция за да не пишеш за всяко поле един и същ код + няма да ти се налага да променяш php-то, ако решиш да добавяш още полета:
PHP:
foreach (array_keys($_FILES) as $file) {
    for ($i = 0; $i < count($_FILES[$file]['name']); $i++) {
        //$file - името на input-а, към който е прикачен файла
        echo $file . ' - ' . $_FILES[$file]['name'][$i] . '<br>';
    }
}
Всичко да наблъскам в FOR-a? заявка, параметри..
 
Нещо не успявам да го направя.. Опитах с foreach loop-a .. добавих в заявката двете нови полета, но получавам грешка, че номера на параметрите не съвпада:
PHP Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

Опитах и с добавянето на
Код:
//file 1
             $fileSize = $_FILES['file']['size'][$i];
             $fileType = $_FILES['file']['type'][$i];
             $fileName = $_FILES['file']['name'][$i];
             $tmpName  = $_FILES['file']['tmp_name'][$i];
             
        $ext = substr(strrchr($fileName, "."), 1);
        $randName = rand(10000, 990000) . '-' .$fileName;
             $filepath = $folderName . $randName;
//file 2
             $fileSize2 = $_FILES['file2']['size'][$i];
             $fileType2 = $_FILES['file2']['type'][$i];
             $fileName2 = $_FILES['file2']['name'][$i];
             $tmpName2  = $_FILES['file2']['tmp_name'][$i];
             
        $ext = substr(strrchr($fileName2, "."), 1);
        $randName2 = rand(10000, 990000) . '-' .$fileName2;
             $filepath2 = $folderName2 . $randName2;
//file 3
             $fileSize3 = $_FILES['file3']['size'][$i];
             $fileType3 = $_FILES['file3']['type'][$i];
             $fileName3 = $_FILES['file3']['name'][$i];
             $tmpName3  = $_FILES['file3']['tmp_name'][$i];
             
        $ext = substr(strrchr($fileName3, "."), 1);
        $randName3 = rand(10000, 990000) . '-' .$fileName3;
             $filepath3 = $folderName3 . $randName3;
Но записва на три реда в базата данни file2 и file3 са без имена ...
 
SVTerziev каза:
Напиши целия код да видим къде точно си сбъркал.
Ето, какво съм направил. Получавам си съобщение, че са добавени успешно, но ги няма в таблицата, но ги има в папката ... т.е. проблема е към базата нещо.:
The file doc1.docx is added successfully.
The file doc2.docx is added successfully.
The file doc3.docx is added successfully.
кода
Код:
<form class="form-horizontal" name="form-horizontal" action="" method="post" role="form" enctype="multipart/form-data" >
	 <div class="form-group">
		<label class="control-label col-sm-2" for="upload_lesson_plan">Lesson Plan: </label>
			<div class="col-sm-10">
				<input type="file" class="form-control add1" name="file[]" id="upload_plan" >			  	
			</div>
	 </div> 
	 <div class="form-group">
		<label class="control-label col-sm-2" for="upload_worksheet">Worksheets:</label>
			<div class="col-sm-10">
			  	<input type="file" class="form-control add" name="file[]" id="upload_worksheet" >
			</div>						
	  </div>	
	  <div class="form-group">
		<label class="control-label col-sm-2" for="upload_materials">Lesson Materials:</labеl>
			<div class="col-sm-10">
			  	<input type="file" class="form-control add" name="file[]" id="upload_materials" >
			</div>						
	  </div>					  			  				  					  				  					  					  					  				  					  					  					  					  
	  <div class="form-group"> 
		<div class="col-sm-offset-2 col-sm-4">
	    	    <input type="submit" name="add" value="Add New Lesson" class="btn btn-primary btn-block">
		 </div>
	  </div>
</form>
И PHP-то
Код:
if (isset($_POST["add"])) {
$pdo = Database::connect();
  $msg = "";
  $permitted = array();
	
  if (count($_FILES["file"]) > 0) {
	  
	    $folderName = "uploads/";
	
	    $sql = "INSERT INTO document_upload (  upload_worksheet, upload_plan, upload_materials, upload_size, upload_type, document_path, upload_date) 
					  	VALUES ( :upload_worksheet, :upload_plan, :upload_materials,  :upload_size, :upload_type, :document_path, NOW())";
	    $stmt = $pdo->prepare($sql);
        foreach (array_keys($_FILES) as $file) {
	     for ($i = 0; $i < count($_FILES[$file]["name"]); $i++) {
	
	      if ($_FILES["file"]["name"][$i] <> "") {     
	        if ($permitted) {
	  
	          $fileSize = $_FILES[$file]['size'][$i];
	          $fileType = $_FILES[$file]['type'][$i];
	          $fileName = $_FILES[$file]['name'][$i];
	          $tmpName  = $_FILES[$file]['tmp_name'][$i];
	          
		  $ext = substr(strrchr($fileName, "."), 1);
		  //$randName = rand(10000, 990000) . '-' .$fileName;
            $_FILES[$file]['name'][$i] = rand(10000, 990000) . '-' .$fileName;
	          $filepath = $folderName . $randName;
	       
	          if (!move_uploaded_file($tmpName, $filepath)) {
	            $emsg .= "Error while uploadinf file - <strong>" . $_FILES[$file]["name"][$i] . "</strong>. Please try again. <br>";
	          } else {
	            $smsg .= "The file <strong>" . $_FILES[$file]["name"][$i] . "</strong> is added successfully. <br>";
	            /*             * ****** insert into database starts ******** */
	           			         
	            try {
	              $stmt->bindValue(":upload_worksheet",  $_FILES[$file]['name'][$i], PDO::PARAM_STR);  
                      $stmt->bindValue(":upload_plan",  $_FILES[$file]['name'][$i], PDO::PARAM_STR);  
                      $stmt->bindValue(":upload_materials",  $_FILES[$file]['name'][$i], PDO::PARAM_STR);  
	              $stmt->bindValue(":upload_size", $fileSize, PDO::PARAM_STR);
	              $stmt->bindValue(":upload_type", $fileType, PDO::PARAM_STR); 
	              $stmt->bindValue(":document_path", $filepath, PDO::PARAM_STR);  

	              $stmt->execute();
	              $result = $stmt->rowCount();
	              if ($result > 0) {
	                // file uplaoded successfully.
	              } else {
	                // failed to insert into database.
	              }
	            } catch (Exception $ex) {
	              $emsg .= "<strong>" . $ex->getMessage() . "</strong>. <br>";
	            }
	          }
	        } else {
	          $emsg .= "This file <strong>" . $_FILES[$file]["name"][$i] . "</strong> isn't permitted. <br>";
	        }
	      }
	    }
    }
	    $msg .= (strlen($smsg) > 0) ? successMessage($smsg) : "";
	    $msg .= (strlen($emsg) > 0) ? errorMessage($emsg) : "";
	  } else {
	    $msg = errorMessage("You must add at least one file.");
	  }
	 
	}
И още нещо .. как ще запиша пътя до три докуемнта в едно и също поле?
var_dump връща, каквото трябва:
Код:
string(9) "doc1.docx" 
string(9) "doc2.docx" 
string(9) "doc3.docx"
 
Добре, докарах го до да записва в базата документите от всички полета. Проблема беше в грешно поле, което бях написал в sql заявката.

Обаче проблема с трите записа в базата остава. Добавям 3 документа... във всяко поле по един и записва три реда в таблицата с едни и същи данни. Все едно три пъти съм натиснал бутон събмит.
 
Изкарай си заявката за добавяне в БД извън for-а
и ползвай
http://php.net/manual/en/function.serialize.php
 
uphero каза:
Изкарай си заявката за добавяне в БД извън for-а
и ползвай
http://php.net/manual/en/function.serialize.php
Тя е извън for-а.
А тази функция честно казано нищо не ми говори и нямам идея как мога да я използвам в случая.
Разбрах донякъде, че с нея мога/трябва да запазя документите в някакъв array?
 
PHP:
if (count($_FILES['file'])
Винаги ще ти връща true, направи един var_dump за да видиш резултата, когато не добавиш файл към полето.

Функцията, която ти дадох с foreach ще ти свърши работа, ако различните полета са с различни имена (както беше дал за пример в началото). Ако всички са ти с едно име, може да го махнеш и да си остане само for цикъла, съответно $_FILES['file']['name'][$i] вместо $_FILES[$file]['name'][$i].

При мен кода си работи, копира файловете и вкарва правилна информация в базата данни. Пробвай да добавиш във for цикъла да изписва на екрана информацията за текущия файл, същата информация, която вкарваш в базата данни, за да видим какви разминавания има.
 
SVTerziev каза:
Ако всички са ти с едно име, може да го махнеш и да си остане само for цикъла, съответно $_FILES['file']['name'][$i] вместо $_FILES[$file]['name'][$i].
има.
Пак остава въпроса тук, как ще стане:
Код:
$stmt->bindValue(":upload_worksheet", $_FILES[$file]['name'][$i], PDO::PARAM_STR);  
$stmt->bindValue(":upload_plan", $_FILES[$file]['name'][$i], PDO::PARAM_STR);  
$stmt->bindValue(":upload_materials", $_FILES[$file]['name'][$i], PDO::PARAM_STR);
 
Код:
	     for ($i = 0; $i < count($_FILES["file"]["name"]); $i++) {
	
	      if ($_FILES["file"]["name"][$i] <> "") {     
	        if ($permitted) {
	  
	          $fileSize = $_FILES["file"]['size'][$i];
	          $fileType = $_FILES["file"]['type'][$i];
	          $fileName = $_FILES["file"]['name'][$i];
	          $tmpName  = $_FILES["file"]['tmp_name'][$i];
	          

		  $ext = substr(strrchr($fileName, "."), 1);
		  $_FILES["file"]['name'][$i] = rand(10000, 990000) . '-' .$fileName;
            
	          $filepath = $folderName . $_FILES["file"]['name'][$i];
	       
	          if (!move_uploaded_file($tmpName, $filepath)) {
	            $emsg .= "Error while uploadinf file - <strong>" . $_FILES["file"]["name"][$i] . "</strong>. Please try again. <br>";
	          } else {
	            $smsg .= "The file <strong>" . $_FILES["file"]["name"][$i] . "</strong> is added successfully. <br>";
	            /*             * ****** insert into database starts ******** */
	           			         
	            try {
	              $stmt->bindValue(":upload_worksheet", $_FILES["file"]['name'][$i], PDO::PARAM_STR);  
                      $stmt->bindValue(":upload_plan", $_FILES["file"]['name'][$i], PDO::PARAM_STR);  
                      $stmt->bindValue(":upload_materials", $_FILES["file"]['name'][$i], PDO::PARAM_STR);                            
	              $stmt->bindValue(":upload_size", $fileSize, PDO::PARAM_STR);
	              $stmt->bindValue(":upload_type", $fileType, PDO::PARAM_STR); 
	              $stmt->bindValue(":document_path", $filepath, PDO::PARAM_STR);
Промених го, но не записва в базата... само в папката
 
Не записва в базата данни => нещо възпрепятства изпълнението на кода => има грешка. Провери си error.log файла и виж какво пише там.
 

Back
Горе