Господа! Написал класс загрузки файлов на сервер. Готов выслушать аргументированную критику. ЗЫ: не нужно говорить что изобрел велосипед. updated PHP: <?php class fileloader { private $fileinfo = null; /** * @var types * по умолчанию беруться только 'gif', 'jpg', 'png' */ private $types = null; private $uploadErrors = array( UPLOAD_ERR_OK => 'Файл(ы) загружен(ы).', UPLOAD_ERR_INI_SIZE => 'Превышен допустимый размер файла(ов) разрешенный настройками php.', UPLOAD_ERR_FORM_SIZE => 'Превышен допустимый размер файла(ов) (форма).', UPLOAD_ERR_PARTIAL => 'Файл(ы) был загружен частично.', UPLOAD_ERR_NO_FILE => 'Файл(ы) не был(и) загружен(ы)', UPLOAD_ERR_NO_TMP_DIR => 'Не задана временная директория.', UPLOAD_ERR_CANT_WRITE => 'Ошибка записи файла(ов) на диск.', UPLOAD_ERR_EXTENSION => 'Неверный формат файла.', ); private $path = null; // Настройки private $encodeFileName = false; private $multi = null; private $errors = array(); /** * @var max_file_size * по умолчанию береться значение из настроек сервера */ private $max_file_size = null; public function __construct($upldbox) { $this->fileinfo = $_FILES[$upldbox]; $this->multi = (is_array($this->fileinfo['name'])) ? true : false; $this->max_file_size = $this->_sizeBytes(ini_get('upload_max_filesize')); $this->types = array('gif', 'jpg', 'png'); } public function isError() { return count($this->errors) ? true : false; } public function getErrors() { foreach($this->errors as $e) { print '<font color="#ff0000">'.$e.'</font><br>'; } } //Главный метод public function process() { if(!$this->_isWritable()) { Throw new Exception('Директория не существует или защищена от записи'); } if($this->multi) { for($i = 0, $k = 0; $i < count($this->fileinfo['name']); $i++) { if($this->_noFile($i)) $k++; } if($k == count($this->fileinfo['name'])) $this->errors[] = 'Нет ни одного файла для загрузки'; for($i = 0; $i < count($this->fileinfo['name']); $i++) { if(empty($this->fileinfo['name'][$i]) and $this->fileinfo['size'][$i] == 0) continue; $this->fileinfo['name'][$i] = strtolower($this->fileinfo['name'][$i]); if(!$this->_checkError($i)) { $this->errors[] = $this->_getError($this->_Errno($i)); break; } if(!$this->_checkSize($i)) { $this->errors[] = 'Превышен допустимый размер файла '.$this->fileinfo['name'][$i].' (max = '.$this->max_file_size.' байт )'; } if(!$this->_checkType($i)) { $this->errors[] = 'Тип файла '.$this->fileinfo['name'][$i].' не поддерживается'; } }//end for // Проверяем ошибки if(count($this->errors)) { Throw new Exception($this->getErrors()); } for($i = 0; $i < count($this->fileinfo['name']); $i++) { $tmpname = $this->fileinfo['tmp_name'][$i]; if($this->encodeFileName) { $pinfo = pathinfo($this->fileinfo['name'][$i]); $newname = md5($pinfo['filename']).'.'.$pinfo['extension']; } else { $newname = basename($this->fileinfo['name'][$i]); } if(!(is_uploaded_file($tmpname) and move_uploaded_file($tmpname, $this->path.'/'.$newname))) { $this->errors[] = 'Ошибка загрузки'; continue; } }//end for } else { $this->fileinfo['name'] = strtolower($this->fileinfo['name']); if($this->_noFile()) { Throw new Exception('Нет файлов для загрузки'); } if(!$this->_checkError()) { Throw new Exception($this->_getError($this->_Errno())); } if(!$this->_checkSize()) { Throw new Exception('Превышен допустимый размер файла (max = '.$this->max_file_size.' байт )'); } if(!$this->_checkType()) { Throw new Exception('Тип файла не поддерживается'); } $tmpname = $this->fileinfo['tmp_name']; if($this->encodeFileName) { $pinfo = pathinfo($this->fileinfo['name']); $newname = md5($pinfo['filename']).'.'.$pinfo['extension']; } else { $newname = basename($this->fileinfo['name']); } return (is_uploaded_file($tmpname) and move_uploaded_file($tmpname, $this->path.'/'.$newname)) ? true : false; } } private function __set($index, $value) { if(property_exists($this, $index)) { switch($index) { case 'types': if(is_array($value)) { $this->types = $value; } break; case 'path': if(is_dir($value)) { $this->path = $value; } else { $this->path = null; } break; case 'max_file_size': if($value >= $this->_sizeBytes(ini_get('upload_max_filesize'))) { $this->max_file_size = $this->_sizeBytes(ini_get('upload_max_filesize')); } else { $this->max_file_size = $value; } break; case 'encodeFileName': $this->encodeFileName = $value; break; } } else { return false; } } private function __get($index) { if(property_exists($this, $index)) { return $this->$index; } } private function _getError($no) { return $this->uploadErrors[$no]; } // 'bmp', 'gif', 'png', 'jpg', 'jpeg', 'pdf', 'zip', 'rar', 'gz', 'bz', 'bz2', 'doc', 'swf' private function _getFileType($type) { $ret = null; switch($type) { case 'image/jpeg': $ret = 'jpg'; break; case 'image/gif': $ret = 'gif'; break; case 'image/png': $ret = 'png'; break; case 'image/bmp': $ret = 'bmp'; break; case 'image/x-windows-bmp': $ret = 'bmp'; break; case 'application/pdf': $ret = 'pdf'; break; case 'application/zip': $ret = 'zip'; break; case 'application/rar': $ret = 'rar'; break; case 'application/x-gzip': $ret = 'gz'; break; case 'application/x-bzip': $ret = 'bz'; break; case 'application/x-bzip2': $ret = 'bz2'; break; case 'application/msword': $ret = 'doc'; break; case 'application/x-shockwave-flash': $ret = 'swf'; break; } return $ret; } private function _checkError($num = -1) { return ($num == -1) ? ($this->fileinfo['error'] == 0) ? true : false : ($this->fileinfo['error'][$num] == 0) ? true : false; } private function _Errno($num = -1) { return ($num == -1) ? $this->fileinfo['error'] : $this->fileinfo['error'][$num]; } private function _sizeBytes($val) { $val = trim($val); $last = strtolower($val{strlen($val)-1}); switch($last) { case 'g': $val *= 1024; case 'm': $val *= 1024; case 'k': $val *= 1024; } return $val; } private function _isWritable() { return is_writable($this->path) ? true : false; } private function _checkType($num = -1) { return ($num == -1) ? (in_array($this->_getFileType($this->fileinfo['type']), $this->types)) ? true : false : (in_array($this->_getFileType($this->fileinfo['type'][$num]), $this->types)) ? true : false; } private function _checkSize($num = -1) { return ($num == -1) ? ($this->fileinfo['size'] < $this->_sizeBytes(ini_get('upload_max_filesize')) and $this->fileinfo['size'] < $this->max_file_size ) ? true : false : ($this->fileinfo['size'][$num] < $this->_sizeBytes(ini_get('upload_max_filesize')) and $this->fileinfo['size'][$num] < $this->max_file_size and $this->fileinfo['size'][$num] > 0 ) ? true : false; } private function _noFile($num = -1) { return ($num == -1) ? ($this->fileinfo['error'] == 4) ? true : false : ($this->fileinfo['error'][$num] == 4) ? true : false; } private function __toString() { return nl2br(print_r($this->fileinfo, true)); } } ?>
Помоему хорошая работа, подчеркнул для себя интересные моменты... Вот бы почаще люди скидывали бы свои работы чтобы другие могли учиться
shreck Проверка на расширение что-то не правильно работает. Создал в РНР Expert Editor файл PHP: <?php echo "<script>alert('Hacked');</script>"; ?> И сохранил как js.jpg. Твой класс его принял Правда не знаю, загрузил или нет, но: Все загружено
Elkaz, во-первых, картинка будет картинкой, а не php файлом. Во-вторых, тип файла берётся из расширения. +Sten+, и тип файла тоже возмётся из расширения.
shreck Наример, на сервере стоит графический счётчик и админ связал jpg и PHP. Загруженная картинка вставится, например, как аватар и при вызове сделает что угодно. Так что вполне возможно серьезно похакать сайт, даже просто по забывчивости админа. Если загружать только картинки, стоит проверить, картинка ли это посредством GD функций, которые вернут фалос, если это не картинка вовсе.
Я никогда не понимал, зачем делать приватными переменные, которые можно сделать публичными. В первом случае придётся писать дополнительный метод и вызывать его. Во втором случае я могу не только смотреть, есть ли ошибки, но и читать их. В этом всём есть какой-то тайный смысл?
+Sten+ Можно конечно настроить сервер, чтобы он исполнял файлы *.qwead как php. Но согласись, случай который ты привел, весьма редко встречается. Хотя все возможно.
+Sten+ Делай как считаешь нужным. В идеале, в любом классе все члены должны быть закрытыми, а изменение или чтение членов должно идти только через методы или свойства.
shreck Ясно. Дело стиля. пс. Не хватает проверки "На пустоту". Если ничего не вводить, пишет всё загружено.
ГО, ламер, лень было почитать код да? ))) (не рекомендуется повторять в домашних условиях обращение к ГО) Код (Text): array( UPLOAD_ERR_OK => 'Файл(ы) загружен(ы).', UPLOAD_ERR_INI_SIZE => 'Превышен допустимый размер файла(ов) разрешенный настройками php.', Не объявленные константы, отсутствие мульти ланга, хотя мульти ланг это уже придирки пожалуй. Название констант отображает имя файла - не имя класса? Почему тогда имя класса не соответствует имени файла? Код (Text): $encodeFileName $max_file_size Используется разный стиль написания переменных в рамках одного класса . Код (Text): # if(!$this->_isWritable()) { # Throw new Exception('Директория не существует или защищена от записи'); # } //... # private function _isWritable() { # return is_writable($this->path) ? true : false; # } Напрямую к is_writable не обратиться - чтоб никто не догадался? Код (Text): # public function getErrors() { # foreach($this->errors as $e) { # print '<font color="#ff0000">'.$e.'</font><br>'; # } # } Если уж это клас то фигль он выводы делает в браузер? Код (Text): $this->fileinfo = $_FILES[$upldbox] Ну и обращение к суперглобальным переменным из класса - это как то не круто. дальше лень стало смотреть.
Горбунов Олег а если класс на тривиальный функционал написан криво, зачем он нужен как класс да еще и в форуме "Решения" ?
Как говорил кто-то умнее меня - "все уже написано до нас" В общем если предлагаете свое решение проверьте для начала нет ли более лучших на вскидку: http://www.phpclasses.org/browse/package/3228.html http://www.phpclasses.org/searchtag/Fil ... ileUpload/ http://www.google.com/search?hl=ru&q=fi ... %D0%BA&lr=
фигасе, мелкие придирки 0_0 +Sten+, члены никому ничего не должны. свойства объекта - это такие же составляющие интерфейса, как и методы.
Горбунов Олег, чтобы делать то, что ещё никто не делал или делал, но не правильно. а вот какой смысл изобретать велосипед с треугольными колёсами?
А зачем? )) шучу кончено. Ты ГОшка не путай, одно с другим. В данном случае мы рассматриваем "Готовое решение" которое представлено на суд общественности блестит всеми дырами и не является лучшим из имеющихся открытых решений . А программить можно ради кайфухи, денеК и ради закрытых опенсорсов бугага . Данное решение не под один из критериев не подходит вот и все. А говоря о посредственном решении, что оно хорошее, вы все дружно тем самым сливаете человека. Он вместо того чтоб понять свои ошибки будет думать, что достиг каких то результатов. :-/ Я против таких сливов .