Upload Class

teroristd

Registered
Здравейте, искам да си направя Upload класове един за снимки и друг за файлове. Какво трябва да имам в моделите и контролерите? Какви защити трябва да направя за да се предпазя от злонамерени потребители? Знам че темата е дълга но ще съм благодарен ако дадете насоки и добри практики. Ще помоля и примери с код ако може. Благодаря предварително.
 
teroristd каза:
Здравейте, искам да си направя Upload класове един за снимки и друг за файлове. Какво трябва да имам в моделите и контролерите? Какви защити трябва да направя за да се предпазя от злонамерени потребители? Знам че темата е дълга но ще съм благодарен ако дадете насоки и добри практики. Ще помоля и примери с код ако може. Благодаря предварително.
За целта ще ти дам един метод който ще ти помогне много и се надявам от него сам да си додраснеш останалото.

PHP:
//$this->fileTmpName = $_FILES[$name]['tmp_name']; 

private function getMimeType(){
		if(class_exists('finfo') and defined('FILEINFO_MIME_TYPE')){
			$finfo = new \finfo(FILEINFO_MIME_TYPE);
			$mime = $finfo->file($this->fileTmpName);
		}else if(function_exists('mime_content_type')){
			$mime = mime_content_type($this->fileTmpName);
		}
		return $mime;
	}

Това е най-базовият ми метод за проверка на mime_type на файла.
Веднага ще ти дам и пример със снимките:
PHP:
public function isImage(){
		if(stripos($this->getMimeType(), 'image/') !== false){
			list($width, $height, $type) = getimagesize($this->fileTmpName);
			if(in_array($type, array(IMAGETYPE_JPEG,IMAGETYPE_PNG,))){
				return true;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}

Но реално дали ще проверяваш txt, pdf и таканататък кода ти е подобен и базиран на промяната на mime type. :?:
 
При upload особено, ако е в папка, която е достъпна през web root-a трябва да се проверява и file extensiona, а не само mime type. Кофтито е, че не можеш да разчиташ напълно, че ще имаш дефиниран magic файл, от който да ти чете mime type-вете FileInfo. Та за това за да се презастраховаш правиш проверка и по extension.
 
Според мен mime-type е много по-добър начин за определяне на типът на съдържанието. Дори се счита за добра практика да се задава разширение на файла според mime-type-а му. При linux (масата сървъри в интернет) и osx разширението няма никакво значение. Точно с проверка на разширение хората качват скрипт с име snimka.png и mime-type text/x-shellscript, който се изпълнява ако имаш права +x -> 777, а не 666 например.
 
Така е! Казвам, че е добре да се прави проверка И ПО разширение, защото при инсталация на PHP от пакет ( примерно при Debian преди го имаше проблема ), нямаше сетнат env за magic файла и FileInfo се шашка и може да има непредвидим резултат.
 
Горната функция за проверка за типа ще върне null + notice в 30% от случаите - не, че е проблем в последващата логика, но не е добре така.

Иначе за защита - при картинките след проверка на тип и алабала да се прерисуват с някоя графична библотека - например с GD. За останалите файлове - преди да се преместят в директория, видима от уеб сървъра, може да се архивират и в последствие да се подават само като архив. Така ще се избегнат някои специфични моменти в сигурността.

borovaka: откраднал си ми аватара :)
 
Мерси за отговорите. Ще постна до къде съм стигнал в момента. Всичко ми е в един контролер за сега докато тествам. Всички критики са добре дошли :). В случая картинките се качват успешно, обаче с файловете има доста проблеми. Например файл .ai(adobe illustrator) MIME_TYPE-а ми го показва като .pdf. Файл .eps изобщо не ми го признава, все едно не съм избрал нищо, не стига изобщо до проверката за MIME_TYPE-а.

Код:
namespace controllers;

class UploadImage extends \application\BaseController {

    private $_imageFolderPath = null;
    private $_fileTmpLoc = null;
    private $_fileName = null;
    private $_newFileName = null;
    private $_uploadResult = null;
    private $_submit = null;
    private $_finfo = null;
    private $_mimeType = null;
    private $_getImageSize = null;

    public function start() {

        $this->_view->display('upload/form');

        $this->_imageFolderPath = realpath('..\uploads\images') . DIRECTORY_SEPARATOR;
        $this->_fileTmpLoc = $_FILES['file_upload_field']['tmp_name'];
        $this->_fileName = $_FILES['file_upload_field']['name'];
        $this->_submit = $this->_normalize->post('submit');

        $exp = explode('.', $this->_fileName);
        $this->_newFileName = bin2hex(openssl_random_pseudo_bytes(16)) . '.' . end($exp);

        if (isset($this->_submit)) {
            if ($this->_fileTmpLoc == false) {
                echo '<br> Please choose image first';
            } else {
                $this->_finfo = new \finfo(FILEINFO_MIME_TYPE);
                echo $this->_mimeType = $this->_finfo->file($this->_fileTmpLoc);
                if ($this->_mimeType !== 'image/jpeg' && $this->_mimeType !== 'image/png') {
                    echo '<br> Allowed formats is: jpg/jpeg/png';
                } else {
                    $this->_getImageSize = list($width, $height) = getimagesize($this->_fileTmpLoc);
                    if (!$this->_getImageSize) {
                        echo '<br> Your image do not exist';
                    } else {
                        $this->_uploadResult = move_uploaded_file($this->_fileTmpLoc, $this->_imageFolderPath . $this->_newFileName);
                        echo '<br> You succesfuly uploaded your image';
                    }
                }
            }
        }
    }

}
 

Back
Горе