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

verfaa

Профессор
Регистрация
29 Янв 2007
Сообщения
416
Реакции
49
Всем привет. Разбираю скрипт 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']}
?


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

PHP:
<?php
/*
 * jQuery File Upload Plugin PHP Example 4.2.4
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://creativecommons.org/licenses/MIT/
 */

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');
}
?>
 
stdClass - стандартный класс PHP
ничего особенного в себе не несет. по сути ассоциативный массив в красивой обертке.
часто используется там, где требуется объект, но при этом нету какого-то класса, для создания объекта.
тогда просто создается объект класса stdClass, и ему назначется свойства.

Далее, есть ещё несколько непонятных моментов в скрипте:
PHP:
$append_file = is_file($file_path) && $file->size > filesize($file_path);
clearstatcache();
120-121 линия, читаю так: если файл существует и его размер не превышает допустимые, то... непонятно чему равна переменная $append_file ?
И для чего выполняем функцию clearstatcache() ? В нете по ней крайне мало инфы.
эти моменты прекрасно описаны в справке.
результатом выполнения логического оператора && может быть TRUE или FALSE, в зависимости от значений операндов, в соответсвии с поведением логического И
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']}
?
HTTP_X_FILE_NAME - похоже, что это какая-то особая реализация протокола передачи файлов. похоже для Nginx, хотя для него и $_FILES работает
по поводу второй части, внимательней читайте про тернарный оператор. это самые азы. приблеженно ваше понимание верно, но неточно. тернарный оператор именно возвращает значение, а не просто выоплняет кусок кода

Добавлено через 57 секунд
подвожу итог:
RTFM
вы не знаете самых азов, и ваши вопросы прекрасно освещаются в справочнике, несмотря на то что вы типа не можете нагуглить ответы на них
 
попробовал упростить файл обработчик 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". Т.е. получается метод get() вообще не должен вызываться, юзер пришёл, загрузил методом POST свои фото и пошёл далее, а в адресной строке браузера он никаких данных не передаёт и форм с методом GET на странце никаких нет, так когда и при каких действиях юзера он тогда вызывается? Объясните пожалуйста
 
пустой класс без свойств и методов.
PHP:
class stdClass {}

например:
PHP:
class fooBar {}
$object = mysql_fetch_object(mysql_query("SELECT * FROM `table`"));
print get_class($object); // выводит: stdClass

$object = mysql_fetch_object(mysql_query("SELECT * FROM `table`"), 'fooBar');
print get_class($object); // выводит: fooBar
 
Назад
Сверху