PHP хэл эхлэн суралцагчид эсвэл файл upload-тай анх удаагаа зууралдаж байгаа веб хөгжүүлэгчиддээ зориулан үүнийг бичиж орууллаа. Хэрэглэгчээс ирэх мэдээллүүдээс шалгах нягтлахад ярвигтай хэсгүүдийн нэг бол файл upload юм. Хэрвээ бид энд сайтар анхаарахгүй бол сайтад маань хакеруудын хортой скрипт шургалах улмаар хамаг файл буюу сайтаа алдах аюултай.

Ингээд файлын хэмжээ, mimetype болон файлын нэрний өргөтгөл, сервер дээрх файлтай давхардах эсэхийг шалгах зэрэг гол чухал зүйлсийг тусгасан жишээ кодыг холбогдох товч тайлбарын хамт өгье.

Бидэнд index.php ба upload.php нэртэй хоёр файл бас upload нэртэй хавтас шаардлагатай. Index.php файлд хэрэглэгчийн ажиллах форм байрлана.

<html>
<head>
  <title>File Upload</title>
</head>
<body>
  <form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="text" id="filename" onclick="getFile()" readonly>
    <input type="button" value="Browse" onclick="getFile()">
    <div style="height: 0px; width:0px; overflow:hidden;"><input type="file" id="file" name="file" value="upload" onchange="sub(this)"></div>
    <input type="submit" value="Upload">
  </form>
  <script type="text/javascript">
    function getFile(){
      document.getElementById("file").click();
    }
    function sub(obj){
      var file = obj.value;
      var fileName = file.split("\\");
      document.getElementById("filename").value = fileName[fileName.length-1];
      document.myForm.submit();
      event.preventDefault();
    }
  </script>
</body>
</html>

Файл upload хийхэд ашиглагдах file төрлийн input нь CSS зэргээр хэлбэржихдээ учир дутагдалтай тул зориудаар нууж харин жаваскриптийн тусламжтайгаар өөр төрлийн input-үүдээр түүнийг төлөөлүүлсэн нь дээр харагдаж байна. Энэ формын гол онцлог ялгаа нь enctype="multipart/form-data" болон file төрлийн input юм. Одоо цааш үргэлжлүүлэн хамгийн чухал хэсэг болох upload.php файлд анхаарлаа хандуулъя.

Upload.php файл манай ажлыг нугалах болно. Энд серверийн тохиргооноос шалтгаалсан файлын хэмжээний хязгаарлалт, аюулгүй байдлаас шалтгаалсан файлын төрлийг шалгах шаардлага, сервер дээрх файлтай давхардахаас сэргийлэх, гарах алдааг хүнд ойлгомжтойгоор мэдээлэх, нүх цоорхойноос сэргийлэх зэрэгт зайлшгүй анхаарах шаардлагатай.

<?php

$configuration = array(
  'dir' => 'upload/',
  'allowed_file_type' => 'image',
  'file_size_limit' => '10M',
  'file_name_format' => '/[^a-zA-Z0-9 _.-]+/'
);

$configuration['file_size_limit'] = file_size_limit($configuration['file_size_limit']);
if(!isset($_FILES['file'])){
  echo 'No valid data was submitted';
}elseif($_FILES['file']['error'] > 0){
  echo error_code_to_message($_FILES['file']['error']);
}elseif(preg_match($configuration['file_name_format'], $_FILES['file']['name']) !== 0){
  echo 'Name of the uploaded file is invalid';
}elseif($_FILES['file']['size'] > $configuration['file_size_limit']){
  echo 'The uploaded file exceeds the file_size_limit directive in the configuration';
}elseif(!check_file_type($_FILES['file']['name'], $_FILES['file']['tmp_name'], $configuration['allowed_file_type'])){
  echo 'MIME type of the uploaded file is invalid for the configuration';
}elseif(file_exists($configuration['dir'].$_FILES['file']['name'])){
  echo 'A file with the same name already exists';
}elseif(!move_uploaded_file($_FILES['file']['tmp_name'], $configuration['dir'].$_FILES['file']['name'])){
  echo 'Failed to move the uploaded file to specific directory';
}else{
  echo 'Name: ', $_FILES['file']['name'], '<br>',
  'Type: ', $_FILES['file']['type'], '<br>',
  'Size: ', $_FILES['file']['size'], ' B<br>',
  'Temp file: ', $_FILES['file']['tmp_name'], '<br>',
  'Stored in: ', $configuration['dir'], $_FILES['file']['name'];
}
 
 function file_size_limit($custom_max_size = '10M'){
 
  $max_upload = return_bytes(ini_get('upload_max_filesize'));
  $max_post = return_bytes(ini_get('post_max_size'));
  $memory_limit = return_bytes(ini_get('memory_limit'));
  $custom_max_size = return_bytes($custom_max_size);
  return min($max_upload, $max_post, $memory_limit, $custom_max_size);
 
}
 
function return_bytes($value){
 
  $value = trim($value);
  $last = strtolower($value[strlen($value)-1]);
  switch($last){
    case 'g':
      $value *= 1024;
    case 'm':
      $value *= 1024;
    case 'k':
      $value *= 1024;
  }
return $value;
 
}
 
function check_file_type($name, $tempname, $allowedmimetype = 'archive'){
  $allowedmimetype = strtolower($allowedmimetype);
  $mimetype = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $tempname);
  $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION));
  switch($allowedmimetype){
    case 'archive':
      return in_array($mimetype, array('application/zip','application/gzip','application/x-rar-compressed','application/x-tar')) && in_array($extension, array('zip','gzip','rar','tar'));
      break;
    case 'document':
      return in_array($mimetype, array('application/pdf','application/x-dvi','application/x-latex','application/vnd.oasis.opendocument.text','application/vnd.oasis.opendocument.spreadsheet','application/vnd.oasis.opendocument.presentation','application/vnd.oasis.opendocument.graphics','application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','application/vnd.ms-powerpoint','application/vnd.openxmlformats-officedocument.presentationml.presentation','application/vnd.openxmlformats-officedocument.wordprocessingml.document')) && in_array($extension, array('pdf','dvi','tex','odt','ods','odp','odg','xls','xlsx','ppt','pptx','doc','docx'));
      break;
    case 'image':
      return in_array($mimetype, array('image/gif','image/jpeg','image/pjpeg','image/png','image/x-png')) && in_array($extension, array('gif','jpeg','jpg','png'));
      break;
    case 'audio':
      return in_array($mimetype, array('audio/mp4','audio/mpeg','audio/ogg')) && in_array($extension, array('mp4','m4a','mp3','ogg','oga'));
      break;
    case 'video':
      return in_array($mimetype, array('video/mpeg','video/mp4','video/ogg','video/quicktime','video/webm','video/x-matroska','video/x-ms-wmv','video/x-flv')) && in_array($extension, array('mpg','mpeg','mp4','m4v','ogg','ogv','vob','webm','mkv','wmv','flv'));
      break;
    default:
      return false;
      break;
  }
 
}
 
function error_code_to_message($code){

  switch($code){
    case UPLOAD_ERR_INI_SIZE:
      $message = 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
      break;
    case UPLOAD_ERR_FORM_SIZE:
      $message = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
      break;
    case UPLOAD_ERR_PARTIAL:
      $message = 'The uploaded file was only partially uploaded';
      break;
    case UPLOAD_ERR_NO_FILE:
      $message = 'No file was uploaded';
      break;
    case UPLOAD_ERR_NO_TMP_DIR:
      $message = 'Missing a temporary folder';
      break;
    case UPLOAD_ERR_CANT_WRITE:
      $message = 'Failed to write file to disk';
      break;
    case UPLOAD_ERR_EXTENSION:
      $message = 'File upload stopped by extension';
      break;
    default:
      $message = 'Unknown upload error';
      break;
  }
  return $message;

}

?>

Гол шаардлагатай параметрүүдийг configuration массивт төвлөрүүлсэн. Ингээд дээр дурдсан зүйлсийг шалгахаас гадна файлын нэрийг шалгаж байна. Учир нь кирилл үсэг болон элдэв бусын тэмдэгтүүд файлын нэрэнд тохиромжгүйн дээр түүнийг сервер дэмжихгүй байх нь элбэг.

Дээрх кодны онцлох чухал хэсэг бол mimetype болон файлын нэрний өргөтгөлийг шалгах функц юм. Үүнийг PHP 5.3 дээр шинээр орж ирсэн функцүүдийг ашиглан бичсэн. Ийнхүү технологийн сүүлийн үеийн шийдлийг тусгаснаар mimetype шалгалт харьцангуй найдвартай болж чадсан гэдэгт итгэлтэй байна. Үнэхээр ч хэсэг php кодыг файл болгон хадгалаад jpg өргөтгөл өгч байгаад upload хийж үзэхэд mimetype алдаатай байгааг барьж авч чадаж байгааг тэмдэглэе.

Мөн хоосон форм upload хийх зэрэг энгийн алдаануудыг ч шалгаж байгааг хамгийн эхний нөхцөл шалгах хэсгээс харж болно. Эдгээрээс гадна upload хавтсан дахь php файлуудын ажиллах болон HTTP-ээр upload хавтас уруу хандахыг хорихын тулд дараах кодыг upload хавтсанд .htaccess файл үүсгэн хадгалах шаардлагатай.

php_flag engine off

Order Deny,Allow
Deny from all

Эцэст нь үүнийг бичихэд ашигласан гол чухал эх сурвалжийг хавсаргая. FileinfoHandling file uploads, PHP secure file upload.