Silentland
Новичок
Можно практическую задачку разобрать, с которой бьюсь ни один день. Урезал как мог код, надеюсь, можно будет понять. Тут как раз проблема с исключениями. Например, функция saveFile принимает параметр $maxSize и отсеивает большие файлы. Но параметр $maxSize так же высчитывается исходя из оставшегося свободного места. Сейчас это делается в функции add, но понятно, что такой же код будет и в update, т.е. придется выносить его в какую-нибудь функцию validate. Но тогда получится, что эта функция должна будет так же загружать файл, вызывая saveFile, получать от нее информацию о размере файла и генерировать исключение либо «превышен допустимый размер файла» либо «закончилось место на диске». В общем, запутанная история. А без эксепшенов ИМХО будет еще запутаннее. Как бы вы поступили?
PHP:
define ("MAX_FILE_SIZE", min(convertbytes(ini_get('upload_max_filesize')), convertbytes(ini_get('post_max_size'))));
try {
new FileUpload($param);
} catch(Exception $e) {
switch ($e->getCode()) {
case 1: //Размер принятого файла превысил максимально допустимый размер, который задан директивой upload_max_filesize конфигурационного файла php.ini
case 2: //Размер загружаемого файла превысил значение MAX_FILE_SIZE, указанное в HTML-форме.
case 5: //Размер загружаемого файла превысил все мыслимые значения.
case 12: //Размер загружаемого файла превысил допустимое значение.
$error_report = 'Файл ' . $_FILES['name'] . ' превышает разрешенный для загрузки объем ' . round($this->maxFileSize/1048576, 2) . ' Мб';
break;
case 3: //Загружаемый файл был получен только частично.
case 4: //Файл не был загружен.
case 6: //Отсутствует временная папка. Добавлено в PHP 4.3.10 и PHP 5.0.3.
case 7: //Не удалось записать файл на диск. Добавлено в PHP 5.1.0.
case 8: //PHP-расширение остановило загрузку файла.
case 9: //Не удалось переместить из временной директории
$error_report = 'Загрузка не удалась';
break;
case 10: $error_report = 'Файл неразрешенного типа';
break;
case 11: $error_report = 'Обновите браузер';
break;
case 13: $error_report = 'Превышено количество загружаемых файлов';
break;
case 14: $error_report = 'Не хватает места на диске для записи этого файла'; //Откуда должно поступать исключение такого типа???
}
}
class FileUpload {
private $uploadDir = 'uploads/'; //Папка для хранения изображений
private $maxNumberOfFiles = 100; //Максимальное количество загружаемых файлов
private $maxSpace = 1000000; //Место, отведенное для загруженных файлов
private $maxSize = MAX_FILE_SIZE; //Максимально допустимый вес загружаемого файла
private $allowedType = array('jpeg', 'jpg', 'png', 'gif'); //Допустимые расширения для загрузки
public function __construct($param) {
$this->init($param);
}
private function init($param) {
switch ($param['type']) {
case add: $this->add(); break;
case delete: $this->delete($param['id']); break;
case update: $this->update($param['id']); break;
default: throw new Exception('Еще какая-то шняга', 15);
}
}
private function add() {
//Загружаем файл на сервер
list($file_name, $file_size) = $this->saveFile($this->validate(), $this->allowedType);
//Добавляем информацию в базу
mysql_query("insert into `album1` set `title` = '".$data['title']."', file = '".$file_name."', size = '".$file_size."'");
}
private function validate() {
//Проверяем, не превышено ли количество загружаемых файлов
$res = mysql_query("select count(*) as quantity from `album1`");
$row = mysql_fetch_assoc($res);
if ($row['quantity'] >= $this->maxNumberOfFiles) {
throw new Exception('Превышено количество загружаемых файлов', 13);
}
//Проверяем сколько осталось свободного места, и, если нужно, уменьшаем допустимый размер загружаемого файла
$space = mysql_query("select sum(`size`) from `album1`");
list($space) = mysql_fetch_row($space);
if ($this->maxSpace && ($this->maxSpace - $space) < $this->maxSize) {
return $this->maxSpace - $space;
//В этом случае, если файл окажется слишком большим, нужно выдавать ошибку, что закончилось место на диске
} elseif ($this->maxSpace && ($this->maxSpace - $space) >= $this->maxSize) {
return $this->maxSize;
//В этом случае, если файл окажется слишком большим, нужно выдавать ошибку, что превышен разрешенный размер
}
}
private function delete($id) {}
private function update($id) {}
public function saveFile($maxSize, $allowedType) {
if(!empty($_FILES)) {
$file = $_FILES[$this->fieldName];
if ($file['error']) {
throw new Exception('Загружен с ошибкой...', $file['error']);
}
if ($file['size'] > $maxSize){
throw new Exception('Превышен допустимый размер файла', 12);
}
//Если файл без расширения, узнаем его из MIME-типа
if (!($ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)))) $ext = preg_replace('/^.*([^\/]*)$/U', '$1', $file['type']);
if (!in_array($ext, $allowedType)){
throw new Exception('Файл неразрешенного типа', 10);
}
$new_file_name = uniqid() . '.' . ($allowedType[$file['type']] ? $allowedType[$file['type']] : strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)));
if (!move_uploaded_file($file['tmp_name'], $this->uploadDir . $new_file_name)) {
throw new Exception('Не удалось переместить из временной директории', 9);
}
return array($new_file_name, $file['size'], $file['type']);
} else {
$headers = getallheaders();
if($headers['Content-Length'] > $maxSize) {
throw new Exception('Превышен размер файла, установленный на сервере', 5);
}
throw new Exception('Старые браузеры пока не поддерживаются', 11);
}
}