что за класс stdClass и зачем он нужен в скрипте?

rambap

Новичок
Всем привет. Разбираю скрипт jQuery File Upload от blueimp.net и пытаюсь внедрить его к себе на сайт.
В файле обработчике upload.php неоднократно используется класс stdClass который нигде в скрипте не обявлен и не описан.
Объясните плиз, что это за класс и зачем он вообще нужен? Какой функционал он несёт в этот скрипт и почему используется именно он?(смотрел код других скриптов с похожим функционалом - там все прекрасно реализовывалось и без него).

Далее, есть ещё несколько непонятных моментов в скрипте:

PHP:
$append_file = is_file($file_path) && $file->size > filesize($file_path);
clearstatcache();
120-121 линия, читаю так: если файл существует и его размер не превышает допустимые, то... непонятно чему равна переменная $append_file ?
И для чего выполняем функцию clearstatcache() ? В нете по ней крайне мало инфы.

и ещё:

PHP:
isset($_SERVER['HTTP_X_FILE_NAME']) ?
$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
202 линия, что хранит переменная $_SERVER['HTTP_X_FILE_NAME'] ?
И как правильно понимать этот кусок кода?, как сокращённую запись от
PHP:
if(isset($_SERVER['HTTP_X_FILE_NAME']))
{$_SERVER['HTTP_X_FILE_NAME']}
else
{$upload['name']}
?
 

rambap

Новичок
Приведу тут код файла-обработчика upload.php
Ещё было бы классно, если бы кто-нибудь откомментировал основные моменты скрипта :ah:

PHP:
<?php
error_reporting(E_ALL | E_STRICT);

$script_dir = dirname(__FILE__);
$script_dir_url = dirname($_SERVER['PHP_SELF']);
$options = array(
    'upload_dir' => $script_dir.'/files/',
    'upload_url' => $script_dir_url.'/files/',
    'thumbnails_dir' => $script_dir.'/thumbnails/',
    'thumbnails_url' => $script_dir_url.'/thumbnails/',
    'thumbnail_max_width' => 80,
    'thumbnail_max_height' => 80,
    'field_name' => 'file'
);

class UploadHandler
{
    private $upload_dir;
    private $upload_url;
    private $thumbnails_dir;
    private $thumbnails_url;
    private $thumbnail_max_width;
    private $thumbnail_max_height;
    private $field_name;
    
    function __construct($options) {
        $this->upload_dir = $options['upload_dir'];
        $this->upload_url = $options['upload_url'];
        $this->thumbnails_dir = $options['thumbnails_dir'];
        $this->thumbnails_url = $options['thumbnails_url'];
        $this->thumbnail_max_width = $options['thumbnail_max_width'];
        $this->thumbnail_max_height = $options['thumbnail_max_height'];
        $this->field_name = $options['field_name'];
    }
    
    private function get_file_object($file_name) {
        $file_path = $this->upload_dir.$file_name;
        if (is_file($file_path) && $file_name[0] !== '.') {
            $file = new stdClass();
            $file->name = $file_name;
            $file->size = filesize($file_path);
            $file->url = $this->upload_url.rawurlencode($file->name);
            $file->thumbnail = is_file($this->thumbnails_dir.$file_name) ?
                $this->thumbnails_url.rawurlencode($file->name) : null;
            return $file;
        }
        return null;
    }

    private function create_thumbnail($file_name) {
        $file_path = $this->upload_dir.$file_name;
        $thumbnail_path = $this->thumbnails_dir.$file_name;
        list($img_width, $img_height) = @getimagesize($file_path);
        if (!$img_width || !$img_height) {
            return false;
        }
        $scale = min(
            $this->thumbnail_max_width / $img_width,
            $this->thumbnail_max_height / $img_height
        );
        if ($scale > 1) {
            $scale = 1;
        }
        $thumbnail_width = $img_width * $scale;
        $thumbnail_height = $img_height * $scale;
        $thumbnail_img = @imagecreatetruecolor($thumbnail_width, $thumbnail_height);
        switch (strtolower(substr(strrchr($file_name, '.'), 1))) {
            case 'jpg':
            case 'jpeg':
                $src_img = @imagecreatefromjpeg($file_path);
                $write_thumbnail = 'imagejpeg';
                break;
            case 'gif':
                $src_img = @imagecreatefromgif($file_path);
                $write_thumbnail = 'imagegif';
                break;
            case 'png':
                $src_img = @imagecreatefrompng($file_path);
                $write_thumbnail = 'imagepng';
                break;
            default:
                $src_img = $write_thumbnail = null;
        }
        $success = $src_img && @imagecopyresampled(
            $thumbnail_img,
            $src_img,
            0, 0, 0, 0,
            $thumbnail_width,
            $thumbnail_height,
            $img_width,
            $img_height
        ) && $write_thumbnail($thumbnail_img, $thumbnail_path);
        // Free up memory (imagedestroy does not delete files):
        @imagedestroy($src_img);
        @imagedestroy($thumbnail_img);
        return $success;
    }
    
    private function handle_file_upload($uploaded_file, $name, $size, $type, $error) {
        $file = new stdClass();
        $file->name = basename(stripslashes($name));
        $file->size = intval($size);
        $file->type = $type;
        if (!$error && $file->name) {
            if ($file->name[0] === '.') {
                $file->name = substr($file->name, 1);
            }
            $file_path = $this->upload_dir.$file->name;
            $append_file = is_file($file_path) && $file->size > filesize($file_path);
            clearstatcache();
            if ($uploaded_file && is_uploaded_file($uploaded_file)) {
                // multipart/formdata uploads (POST method uploads)
                if ($append_file) {
                    file_put_contents(
                        $file_path,
                        fopen($uploaded_file, 'r'),
                        FILE_APPEND
                    );
                } else {
                    move_uploaded_file($uploaded_file, $file_path);
                }
            } else {
                // Non-multipart uploads (PUT method support)
                file_put_contents(
                    $file_path,
                    fopen('php://input', 'r'),
                    $append_file ? FILE_APPEND : 0
                );
            }
            $file_size = filesize($file_path);
            if ($file_size === $file->size) {
                $file->url = $this->upload_url.rawurlencode($file->name);
                $file->thumbnail = $this->create_thumbnail($file->name) ?
                    $this->thumbnails_url.rawurlencode($file->name) : null;
            }
            $file->size = $file_size;
        } else {
            $file->error = $error;
        }
        return $file;
    }
    
    public function get() {
        $file_name = isset($_REQUEST['file']) ?
            basename(stripslashes($_REQUEST['file'])) : null; 
        if ($file_name) {
            $info = $this->get_file_object($file_name);
        } else {
            $info = array_values(array_filter(array_map(
                array($this, 'get_file_object'),
                scandir($this->upload_dir)
            )));
        }
        header('Cache-Control: no-cache, must-revalidate');
        header('Content-type: application/json');
        echo json_encode($info);
    }
    
    public function post() {
        $upload = isset($_FILES[$this->field_name]) ?
            $_FILES[$this->field_name] : array(
                'tmp_name' => null,
                'name' => null,
                'size' => null,
                'type' => null,
                'error' => null
            );
        if (is_array($upload['tmp_name']) && count($upload['tmp_name']) > 1) {
            $info = array();
            foreach ($upload['tmp_name'] as $index => $value) {
                $info[] = $this->handle_file_upload(
                    $upload['tmp_name'][$index],
                    $upload['name'][$index],
                    $upload['size'][$index],
                    $upload['type'][$index],
                    $upload['error'][$index]
                );
            }
        } else {
            if (is_array($upload['tmp_name'])) {
                $upload = array(
                    'tmp_name' => $upload['tmp_name'][0],
                    'name' => $upload['name'][0],
                    'size' => $upload['size'][0],
                    'type' => $upload['type'][0],
                    'error' => $upload['error'][0]
                );
            }
            $info = $this->handle_file_upload(
                $upload['tmp_name'],
                isset($_SERVER['HTTP_X_FILE_NAME']) ?
                    $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
                isset($_SERVER['HTTP_X_FILE_SIZE']) ?
                    $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'],
                isset($_SERVER['HTTP_X_FILE_TYPE']) ?
                    $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'],
                $upload['error']
            );
        }
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
                $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
            header('Content-type: application/json');
        } else {
            header('Content-type: text/plain');
        }
        echo json_encode($info);
    }
    
    public function delete() {
        $file_name = isset($_REQUEST['file']) ?
            basename(stripslashes($_REQUEST['file'])) : null;
        $file_path = $this->upload_dir.$file_name;
        $thumbnail_path = $this->thumbnails_dir.$file_name;
        $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
        if ($success && is_file($thumbnail_path)) {
            unlink($thumbnail_path);
        }
        header('Content-type: application/json');
        echo json_encode($success);
    }
}

$upload_handler = new UploadHandler($options);

switch ($_SERVER['REQUEST_METHOD']) {
    case 'HEAD':
    case 'GET':
        $upload_handler->get();
        break;
    case 'POST':
        $upload_handler->post();
        break;
    case 'DELETE':
        $upload_handler->delete();
        break;
    default:
        header('HTTP/1.0 405 Method Not Allowed');
}
?>
 

tz-lom

Продвинутый новичок
PHP:
$append_file = is_file($file_path) && $file->size > filesize($file_path);
clearstatcache();
120-121 линия, читаю так: если файл существует и его размер не превышает допустимые, то... непонятно чему равна переменная $append_file ?
правильно читаешь, но это не условие а просто логическая операция, а $append_file и равен результату этой логической операции
И для чего выполняем функцию clearstatcache() ? В нете по ней крайне мало инфы.
http://php.net/manual/en/function.clearstatcache.php
PHP:
isset($_SERVER['HTTP_X_FILE_NAME']) ?
$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
202 линия, что хранит переменная $_SERVER['HTTP_X_FILE_NAME'] ?
И как правильно понимать этот кусок кода?, как сокращённую запись от
PHP:
if(isset($_SERVER['HTTP_X_FILE_NAME']))
{$_SERVER['HTTP_X_FILE_NAME']}
else
{$upload['name']}
нет,не совсем так,там ещё и возврат значения идёт,подробнее тут http://ru.wikipedia.org/wiki/Тернарный_условный_оператор
 

rambap

Новичок
попробовал упростить файл обработчик upload.php до самого простого
PHP:
function post() {

//$upload = $_FILES["upload"];
        if(isset($_FILES["file"])) {
            $upload = $_FILES["file"];
        } else {
            $upload = array(
                'tmp_name' => null,
                'name' => null,
                'size' => null,
                'type' => null,
                'error' => null
            );
        }

        // Если пользователь загрузил больше одного файла
        if (is_array($upload['tmp_name']) && count($upload['tmp_name']) > 1) {
            $info = array();
            foreach ($upload['tmp_name'] as $index => $value) {
                $info[] = array(
                    'tmp_name' => $upload['tmp_name'][$index],
                    'name' => $upload['name'][$index],
                    'size' => $upload['size'][$index],
                    'type' => $upload['type'][$index],
                    'error' => $upload['error'][$index]
                );
                move_uploaded_file($upload['tmp_name'][$index], dirname(__FILE__).'/files/'.$upload['size'][$index]);
            }
        } else {
            // Если пользователь добавил один файл
            if (is_array($upload['tmp_name'])) {
                $info[] = array(
                    'tmp_name' => $upload['tmp_name'][0],
                    'name' => $upload['name'][0],
                    'size' => $upload['size'][0],
                    'type' => $upload['type'][0],
                    'error' => $upload['error'][0]
                );
                move_uploaded_file($upload['tmp_name'][0], dirname(__FILE__).'/files/'.$upload['size'][0]);
            }
            }
        if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
                $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
            header('Content-type: application/json');
        } else {
            header('Content-type: text/plain');
        }
        // Для отладки - смотрим что отдаёт в результате json_encode($info) в js !! Пишет nullnullnullnullnullnull
        $fh = fopen("3.txt", "a+");
        fwrite($fh, json_encode($info));
        fclose($fh);

        echo json_encode($info);
}

post();
Для отладки инфу, которую php отправляет обратно в скрипт я пишу ещё и в файл 3.txt, в результате при отправке через форму файлов скрипт подвисает, а в 3.txt пишет nullnullnullnullnullnull

HTML-форма выглядит как и в оригинальном скрипте так:
HTML:
<form action="upload.php" method="POST" enctype="multipart/form-data">
        <input type="file" name="file[]" multiple>
        <button type="submit">Upload</button>
        <div class="file_upload_label">Upload files</div>

    </form>

И ещё, ну никак не могу понять, зачем в оргинальном скрипте в классе UploadHandler метод get() ??? Ведь все файлы приходят приходят методом POST, в HTML-форме отправки файла указан method="POST". Объясните пожалуйста
 

tz-lom

Продвинутый новичок
дык он и не для загрузки,посмотри что он делает - станет понятнее
 

rambap

Новичок
дык он и не для загрузки,посмотри что он делает - станет понятнее
Я метод get() читаю так:
Если существует в суперглобальном массиве $_REQUEST переменная file (т.е. файл был передан юзером обработчику upload.php) то $file_name равна имени этого файла, иначе $file_name = null;

И сразу возникает вопрос: почему тут был использован суперглобальный массив $_REQUEST, а не $_FILES['file'] ???

Далее, если в $file_name содержится имя файла - вызываем метод get_file_object() и получаем в переменную $info набор свойств - имя, размер, ссылку на файл и тумбу.
Иначе, если $file_name = null - тоже не могу логику уловить, т.е. если $file_name = null - выбрираем все значения массива, отфильтрованные с помощью функции scandir, т.е. те файлы которые расположены в папке куда загружаем файлы, далее следует ф-я array_map, у которой согласно документации вообще первым параметром должна функция ити...

Далее отправляем заголовки, и отправляем $info в js.

И всё равно, не могу понять зачем нам метод get() и при каких действиях юзера он вызывается? Т.е. получается он вообще не должен вызываться, юзер пришёл, загрузил методом POST свои фото и пошёл далее, а в адресной строке браузера он никаких данных не передаёт и форм с методом GET на странце никаких нет, так когдаже он тогда вызывается?

Если у кого есть полное понимание класса UploadHandler откомментруйте его плиз, там всего 9кб кода, очень хочется и нужно в нём разобраться)
 

tz-lom

Продвинутый новичок
дык в $_REQUEST файл и не передаётся, это эквивалентно запросу ...?file=filename , и $_REQUEST['file'] это это значение параметра к скрипту
возвращает эта штука либо инфу по одному файлу (имя которого как раз в параметре file ) либо по всем в папке куда ведётся загрузка
хз где он вызывается,но делалось это наверное для какого - нибудь AJAX интерфейса к загрузчику
 
Сверху