<?php
require 'DBase.php';

//ini_set('error_reporting', E_ALL);
//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);

// определяем максимальные размеры загружаемых файлов и время загрузки
ini_set('post_max_size', '1024M');
ini_set('upload_max_filesize', '1024M');
set_time_limit(3600); // 60 минут

try {
    defined('DS') || define('DS', DIRECTORY_SEPARATOR);

    new download();

} catch (Exception $e) {
    http_response_code(400);
    die($e->getMessage());
}

class download
{

    /** @var string Путь для сохранения загруженного архива */
    private $zipUploadPath = __DIR__ . '/tempSave';

    // для распаковки
    private $tempUnzip = __DIR__ . '/tempSave/tempUnzip';

    // куда будет сохраняться скрипт, название класса
    private $generatedClassPath;


    /**
     * Путь до файла класса для обработки относительно структуры архива
     */
    private $processingClassFilePath = 'script.php';


    /** @var string Namespace для нового класса */
    private $classNamespace = 'lib\Controllers\CreateFiles\AllScripts';

    // Название нового класса
    private $generatedClassName;

    // куда сохраняем файлы из разрешенных директорий
    private $dirSaveFiles;

    // путь к скрипту, нужен для бд
    private $pathScript;

    // id продукта появляется после его создания
    private $idProduct;

    // главный метод который будет запускать всю генерацию, нужно указать в бд
    private $installStaticMethod;

    // изначальное название архива
    private $initialTitle;

    private $domain = 'https://o.site5.com';

    // какие бывают форматы
    private $allFileFormats;

    // каким будет формат файла при сохранении
    private $format = NULL;

    // какие директории разрешено разархивировать
    private $allowedDirectoriesAndExtensions = [
        'fonts' => [
//            'path'    => 'fonts',
            'formats' => '*',
        ],
        'bg' => [
//            'path'    => 'bg',
            'formats' => [
                'jpg',
                'png',
                'gif',
                'svg',
            ],
        ],
//        'dompdf' => [
////            'path'    => 'files',
//            'formats' => '*',
//        ],
//        'vendor' => [
////            'path'    => '',
//            'formats' => '*',
//        ],
    ];

    function __construct()
    {
        // если архив - то скачивается архив.

        // если скрин - то передаются url и скрипт сам скачивает эти изображения и шрифты

        new DBase(); // открываем бд


        // какие бывают форматы
        $this->fileFormats();

        if ($_GET['type'] == 'demofile') {

            $this->updateDemoFile();


        } else if ($_GET['type'] == 'jsonimage') {

            $this->downldJson();

        } else if ($_GET['type'] == 'pdf') {

            // загрузка архива
        $this->downldArchive();

        }




    }


    private function updateDemoFile()
    {
        $getContent = file_get_contents('php://input');

        $decode = json_decode($getContent, 1);

        if (!is_array($decode)) {
            throw new Exception('Неверный формат данных');
        }

        if (!(isset($decode['ID'])  AND isset($decode['URL_FILE']) AND isset($decode['TYPE'])) ) {
            throw new Exception('Нет одного из составляющего');
        }

        if (!$idProd = DBase::getValue("SELECT `ID` FROM `PROD_scripts` WHERE `ID` = '{$decode['ID']}'")) {
            throw new Exception('Продукт не найден');
        }

        $typeFile = [
            'photo' => 1,
            'document' => 2,
            'video' => 3
        ];

        if (!isset($typeFile[$decode['TYPE']])) {
            throw new Exception('Неизвестный тип');
        }

        $prodPath = "PROD_files/prod-id-" . $decode['ID'] . "/demonstration";

        // Куда будем сохранять файлы
        $destinationPath = __DIR__ . "/../UMLyMG912T/" . $prodPath;

        // есть ли такая директория?
        if (!is_dir($destinationPath)) {
            // если нет директории, то создаем
            if (!mkdir($destinationPath, 0777, true)) {
                throw new Exception('Не удалось создать директорию для распаковки файла');
            }
        }

//        var_dump($decode);
//        exit;

        // извлекаем имя файла
        $nameFile = explode('/', $decode['URL_FILE']);
        $nameFile = end($nameFile);
        $nameFile = explode('.', $nameFile);
        $nameFile = 'Demonstration.' . end($nameFile); // расширение файла

        // путь с __DIR__
        $dirPathFile = $destinationPath . '/' . $nameFile;

//        var_dump($dirPathFile);
//        exit;

//        var_dump($decode['URL_FILE']);
//        exit;

        // Сохраняем файл
        if (file_put_contents($dirPathFile, fopen($this->encodeUrl($decode['URL_FILE']), 'r')) === false) {
            throw new Exception('Ошибка при сохранении файла.');
        }

        // имеется ли старый файл?
//        if ($oldFile = DBase::getRow("SELECT * FROM `PROD_scripts` WHERE `ID` = '{$decode['ID']}'")) {
////        if ($oldFile = DBase::getRow("SELECT `ID`, `URL` FROM `file_id` WHERE `ANSWER_ID` = '{$idMethod}'")) {
//
//            // удаляем старый файл
//            $pathOldFile = __DIR__ . "/../UMLyMG912T/" . $oldFile['URL'];
//            unlink($pathOldFile);
//
//            $resultDel = DBase::run("DELETE FROM `file_id` WHERE `ID` = " . $oldFile['ID']);
//
//            if (!$resultDel->rowCount()) {
//                throw new Exception('Не удалось удалить старый файл из таблицы');
//            }
//        }

        $query = "INSERT INTO `file_id` (
                        `TYPE`,
                        `URL`
                      )
                    VALUES (
                        :TYPE,
                        :URL
                    )";

        $args = [
            'TYPE' => $typeFile[$decode['TYPE']], // в формате json
            'URL' => $prodPath . '/' . $nameFile
        ];

        DBase::sql($query, $args);

        $idNewFile = DBase::lastInsertId();

        if (!$idNewFile) {
            echo json_encode(['error' => 'false update']);
            exit;
        }

        $updateProdScript = DBase::fastQuery('UPDATE', 'PROD_scripts', ['DEMO_FILE' => $idNewFile], ['ID' => $idProd]);

        if ($updateProdScript->rowCount()) {
            $result = ['result' => 'success'];
        } else {
            $result = ['error' => 'false'];
        }

        echo json_encode($result);
    }


    private function downldJson()
    {

        # создать запись в PROD и получить ID для создания директорий
        # запись json в специальную таблицу image

            # создать директории prod-id-*

            # сохранить файлы: изображения и шрифты

        # сохранить все поля/строки в специальную таблицу

        $getContent = file_get_contents('php://input');


        $decode = json_decode($getContent, 1);

        if (!is_array($decode)) {

            throw new Exception('Неверный формат данных');
        }

        if (!isset($decode['JSON_CODE']) OR !isset($decode['fieldDesignations']) OR !isset($decode['URL_IMAGE'])) {

            throw new Exception('Нет одного из составляющего');
        }

        // раскодируем json_code
        $arrJsonCode = json_decode($decode['JSON_CODE'], 1);

//        print_r($arrJsonCode);
//        exit;

        // должен быть массивом и с ключом fields
        if (!(is_array($arrJsonCode) AND isset($arrJsonCode['fields']))) {

            throw new Exception('Нет fields');
        }

        // создаем новый продукт, закрепляем его ID
        if (!$this->createProduct()) {
            throw new Exception('Не удалось создать запись нового продукта');
        }


        // Куда будем сохранять файлы
        $this->dirSaveFiles = __DIR__ . "/../UMLyMG912T/PROD_files/prod-id-" . $this->idProduct;

        foreach ($arrJsonCode['fields'] as $nameField => $field) {

            if (isset($field['font'])) {

                // проверяем расширение шрифта
                $fontExt = ['ttf' => 1, 'otf' => 1, 'eot' => 1, 'woff' => 1, 'woff2' => 1];

                $fontExtension = pathinfo($field['font'], PATHINFO_EXTENSION);

                if (!isset($fontExt[$fontExtension])) {
                    throw new Exception('Неизвестный формат шрифта - ' . $fontExtension);
                }

                // куда сохраняем
                $destinationPath = $this->dirSaveFiles . '/fonts';

                // есть ли такая директория?
                if (!is_dir($destinationPath)) {
                    // если нет директории, то создаем
                    if (!mkdir($destinationPath, 0777, true)) {
                        throw new Exception('Не удалось создать директорию для распаковки файла');
                    }

                }

                // Сохраняем шрифты
                if (file_put_contents($destinationPath . '/' . basename($field['font']), fopen($this->domain . $field['font'], 'r')) === false) {

                    throw new Exception('Ошибка при сохранении шрифта  - ' . $field['font']);
                }

                // изменяем эту строку, оставляем только название файла
                $arrJsonCode['fields'][$nameField]['font'] = pathinfo($field['font'], PATHINFO_BASENAME);
            }

            // массив полей для добавления в бд
            $addArray[$nameField] = [
                'line_name' => $decode['fieldDesignations'][$nameField],
            ];
        }

        if (isset($decode['URL_IMAGE'])) {

            // проверяем расширение изображения
            $imgExt = ['jpeg' => 1, 'jpg' => 1, 'png' => 1, 'gif' => 1];

            $imageExtension = strtolower(pathinfo($decode['URL_IMAGE'], PATHINFO_EXTENSION)); // в нижнем регистре

            if (!(isset($imgExt[$imageExtension]) AND $this->format = $this->allFileFormats[$imageExtension])) {
                throw new Exception('Неизвестный формат изображения - ' . $imageExtension);
            }

            // куда сохраняем
            $destinationPath = $this->dirSaveFiles . '/imgs';

            // есть ли такая директория?
            if (!is_dir($destinationPath)) {
                // если нет директории, то создаем
                if (!mkdir($destinationPath, 0777, true)) {
                    throw new Exception('Не удалось создать директорию для распаковки файла');
                }
            }

            // Сохраняем файл
            if (file_put_contents($destinationPath . '/' . pathinfo($decode['URL_IMAGE'], PATHINFO_BASENAME), fopen($this->domain . $decode['URL_IMAGE'], 'r')) === false) {

                throw new Exception('Ошибка при сохранении изображения  - ' . $decode['URL_IMAGE']);
            }
        }

//        if (isset($decode['statusBar'])) {
//            $statusBar = [
//                'PLATFORM' => $decode['statusBar']['PLATFORM'],
//                'DARK_THEME' => $decode['statusBar']['DARK_THEME']??0
//            ];
//        }

        // добавление изображения в специальную таблицу
//        if (!$idImageCode = $this->addProdImageCode($arrJsonCode, pathinfo($decode['URL_IMAGE'], PATHINFO_BASENAME)/*, $statusBar??null*/)) {
//
//            throw new Exception('Не удалось сохранить массив полей в таблице изображения');
//        }


        $arrayProdScript = [
//            'IMAGE_CODE' => $idImageCode,
            'IMAGE_JSON_CODE' => json_encode($arrJsonCode),
            'IMAGE_PATH' => json_encode([pathinfo($decode['URL_IMAGE'], PATHINFO_BASENAME)]),
            'FORMAT' => $this->format
        ];

        if (isset($decode['statusBar'])) {
            $arrayProdScript['STATUS_BAR_PLATFORM'] = $decode['statusBar']['PLATFORM'];
            $arrayProdScript['DARK_THEME'] = $decode['statusBar']['DARK_THEME'];
        }


        if (!DBase::fastQuery('UPDATE', 'PROD_scripts', $arrayProdScript, ['ID' => $this->idProduct])) {

            throw new Exception('Ошибка при редактировании id кода в главной таблице PROD');
        }

        // добавляем поля на основе массива $descriptionOfFields
        if (!$this->createFields($addArray)) {
            throw new Exception('Не удалось добавить поля. Возникла проблема. Возможно дублирующие записи');
        }

        if ($this->idProduct) {
            $result = ['newProductID' => $this->idProduct];
        } else {
            $result = ['error' => 'false'];
        }

        echo json_encode($result);

//        var_dump($this->idProduct);
    }


//    private function addProdImageCode($arrJsonCode, $imageName/*, $statusBar = null*/)
//    {
//        $imageExtension = strtolower(pathinfo($imageName, PATHINFO_EXTENSION));
//        if (!isset($this->allFileFormats[$imageExtension])) {
//            return false;
//        }
//
//        $query = "INSERT INTO `PROD_image_code` (
//                        `JSON_CODE`,
//                        `IMAGE_PATH`,
//                        `EXP`
//                      )
//                    VALUES (
//                        :JSON_CODE,
//                        :IMAGE_PATH,
//                        :EXP
//                    )";
//
//        $args = [
//            'JSON_CODE' => json_encode($arrJsonCode),
//            'IMAGE_PATH' => json_encode([$imageName]), // в формате json
//            'EXP' => $this->allFileFormats[$imageExtension]
//        ];
//
//        DBase::sql($query, $args);
//
//        if ($newId = DBase::lastInsertId()) {
//            return $newId;
//        }
//
//        return false;
//    }



    private function downldArchive()
    {
        $getContent = file_get_contents('php://input');
        $decode = json_decode($getContent, 1);

        if (!isset($decode['URL'])) {
            echo 'error';
            exit;
        }

        $url = $decode['URL'];

        // откуда скачиваем архив
//        $url = 'https://o.site5.com/testclass/saves/archive.zip';

        $this->initialTitle = basename($url); // сохраним название файла

        // ПЕРЕМЕЩЕНИЕ АРХИВА В ДИРЕКТОРИЮ С КЛАССОМ ИЛИ С ФАЙЛАМИ

        // метод который будет служить за инсталяцию класса продукта, добавляется в бд
        $this->installStaticMethod = 'create';

        // устанавливаем формат этого файла
        $this->format = $this->allFileFormats['pdf'];

//        var_dump($this->format);
//        exit;

        // генерируем название для класса
        $x=0;
        while ($x++<10) {
            $this->generatedClassName = $this->randomText(); // так будет называться временный файл и будущий класс

            $this->pathScript = "CreateFiles/AllScripts/" . $this->generatedClassName; // путь к скрипту, сохраняется в бд

            $this->generatedClassPath = __DIR__ . "/../UMLyMG912T/lib/Controllers/" . $this->pathScript;

            if (!file_exists($this->generatedClassPath)) break; // если такой директории не существует, выходим из цикла
            $this->generatedClassPath = null;
        }

        if ($this->generatedClassPath == null) {
            throw new Exception('Из 10 попыток не нашлось названия для директории.');
        }


        $fileExtension = pathinfo($url, PATHINFO_EXTENSION);
        if ($fileExtension !== 'zip') {
            throw new Exception('Разрешены только ZIP архивы'); // Разрешены только ZIP-архивы.
        }


        // проверяем на месте ли директория для временного хранилища
        if (!is_dir($this->zipUploadPath)) {
            if (!mkdir($this->zipUploadPath, 0777, true)) {
                throw new Exception('Не удалось создать директорию для загрузки архива: ' . $this->zipUploadPath);
            }
        }


//        $zipFilePath = $this->zipUploadPath . '/sAPOInWRKu.zip';


         // НА ВРЕМЯ РАЗРАБОТКИ ОСТАВИМ ТОЛЬКО ОДИН ЗАГРУЖЕННЫЙ ФАЙЛ И БУДЕМ РАБОТАТЬ ПО НЕМУ

        $zipFilePath = $this->zipUploadPath . '/' . $this->generatedClassName . '.zip';

        if (!$this->downloadFile($zipFilePath, $url)) {
            throw new Exception('Не удалось сохранить ZIP-архив на сервере.');
        }


        // уже сохранили во временном хранилище
        // Дальше распаковка уже


        $extraFiles = [];
        $zip = new ZipArchive();
        if ($zip->open($zipFilePath) === true) {
            /**
             * Извлечение файла класса во временную директорию
             */
            $tempDir = $this->tempUnzip . '/' . uniqid('zip_processing');

            if (!is_dir($tempDir)) {
                if (!mkdir($tempDir, 0777, true)) {
                    throw new Exception('Не удалось создать временную директорию для распаковки файла класса: ' . $tempDir);
                }
            }

            $scriptPathInZip = ltrim($this->processingClassFilePath, '/');
            $tempScriptPath = $tempDir . '/' . basename($this->processingClassFilePath);

            if ($zip->locateName($scriptPathInZip) !== false) {
                file_put_contents($tempScriptPath, $zip->getFromName($scriptPathInZip));
            } else {
                $zip->close();

                throw new Exception('Файл класса ' . $this->processingClassFilePath . ' не найден в архиве.');
            }


            /**
             * Обработка класса
             */

            // Загрузка исходного кода класса
            $sourceCode = file_get_contents($tempScriptPath);
            if (!$sourceCode) {
                throw new Exception('Ошибка чтения скрипта для обработки: ' . $tempScriptPath);
            }

            // Извлечение параметра descriptionOfFields класса
            $descriptionOfFields = [];
            preg_match('/\$descriptionOfFields\s*=\s*\[.*?];/sxui', $sourceCode, $matches);
            if (!empty($matches[0])) {
                // Преобразуем строку с массивом в реальный массив
                eval('$descriptionOfFields = ' . substr($matches[0], strpos($matches[0], '[')) . ';');
            } else {
                throw new Exception('Переменная $descriptionOfFields не найдена.');
            }

            if (!(count($descriptionOfFields)>0)) {

                throw new Exception('Нет полей! Поля обязаны быть!');
            }


            // ВОТ ЗДЕСЬ ТОЛЬКО ПРОВЕРИЛИ ГЛАВНЫЕ ПАРАМЕТРЫ СКРИПТА
            // ПРОВЕРИЛИ ФАЙЛ КЛАССА, можем создавать продукт

            // создаем новый продукт
            if (!$this->createProduct(1)) {
                throw new Exception('Не удалось создать запись нового продукта');
            }


            // добавляем поля на основе массива $descriptionOfFields
            if (!$this->createFields($descriptionOfFields)) {
                throw new Exception('Не удалось добавить поля. Возникла проблема. Возможно дублирующие записи');
            }

            // Куда будем сохранять файлы
            $this->dirSaveFiles = __DIR__ . "/../UMLyMG912T/PROD_files/prod-id-" . $this->idProduct;


            // Извлечение подключенных библиотек в use класса
            preg_match_all('/use\s+([^;]+);/', $sourceCode, $processingClassUseMatches);
            $processingClassUseStatements = $processingClassUseMatches[1] ?? [];

            // Извлечение статических методов класса
            preg_match_all(
                '/(public|private|protected)?\s*static\s+(public|private|protected)?\s*function\s+(\w+)\s*\((.*?)\)\s*(\{(?:[^{}]++|(?5))*+})(?=\s*(?:[pP]ublic|[pP]rivate|[pP]rotected|static|}[^}]*$|\s*\w+\s*\([^)]*\)\s*;|\s*\w+\s*=.*?;))/sxui',
                $sourceCode,
                $methodMatches,
                PREG_SET_ORDER
            );
            $staticMethods = [];
            foreach ($methodMatches as $match) {
                $staticMethods[$match[3]] = [
                    'visibility' => $match[1] ?: $match[2] ?: 'public',
                    'params' => $match[4],
                    'code' => $match[5],
                ];
            }

            // Подготовка статических методов для нового класса
            $methods = '';
            foreach ($staticMethods as $method => $data) {
                $methods .= "    static {$data['visibility']} function $method({$data['params']})\r\n    {$data['code']}\n\n";
            }

            // Создание кода нового класса
            $template = "<?php\r\n\r\nnamespace $this->classNamespace;";
            if (!empty($this->generatedClassLibrariesUse)) {
                $template .= "\r\n\r\nuse " . implode(", ", $this->generatedClassLibrariesUse) . ";";
            }
            $template .= "\r\n\r\nclass $this->generatedClassName\r\n{\r\n$methods\r\n}\r\n";



            // Создаем директорию для класса
            if (!is_dir($this->generatedClassPath)) {
                if (!mkdir($this->generatedClassPath, 0777, true)) {
                    throw new Exception('Не удалось создать директорию для нового класса: ' . $this->generatedClassPath);
                }
            }

            // Сохранение нового класса
            file_put_contents($this->generatedClassPath . '/' . $this->generatedClassName . '.php', $template);

            // Удаление временного файла оригинального класса
            @unlink($tempScriptPath);
            if (is_dir($tempDir)) {
                @rmdir($tempDir);
            }


            /**
             * Распаковка файлов из архива
             */
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $fileInZip = $zip->getNameIndex($i);
                $allowed = false;
                foreach ($this->allowedDirectoriesAndExtensions as $allowedDir => $settings) {
                    if (stripos($fileInZip, $allowedDir) === 0) {
                        $allowed = true;
                        $fileExtensionInZip = pathinfo($fileInZip, PATHINFO_EXTENSION);

                        if (
                            '*' === $settings['formats']
                            || in_array($fileExtensionInZip, $settings['formats'])
                        ) {
                            $destinationPath = $this->dirSaveFiles // в какую директорию сохраняем
//                                . ltrim($settings['path'], DS) // создавало лишнюю директорию
                                . DS
                                . str_replace('/', DS, $fileInZip);

                            if (DS === substr($destinationPath, -1)) {
                                // Это директория, создаём её
                                if (!is_dir($destinationPath)) {
                                    if (!mkdir($destinationPath, 0777, true)) {
                                        throw new Exception('Не удалось создать директорию для распаковки: ' . $destinationPath);
                                    }
                                }
                            } else {
                                // Это файл, создаём родительскую директорию
                                if (!is_dir(dirname($destinationPath))) {
                                    if (!mkdir(dirname($destinationPath), 0777, true)) {
                                        throw new Exception('Не удалось создать директорию для распаковки файла: ' . $destinationPath);
                                    }
                                }
                                // Записываем файл
                                file_put_contents($destinationPath, $zip->getFromIndex($i));
                            }
                        }
                        break;
                    }
                }

                if (!$allowed) {
                    $extraFiles[] = $fileInZip;
                }
            }

            $zip->close();

//            var_dump($this->dirSaveFiles . '/archive');

            // перемещаем архив и переименовываем его в начальное название
            if (mkdir($this->dirSaveFiles . '/archive', 0777, true)) {
                if (!rename($zipFilePath, $this->dirSaveFiles . '/archive/' . $this->initialTitle)) {

                    throw new Exception('Не удалось переместить и переименовать оригинальный архив');
                }
            } else {

                throw new Exception('Не удалось создать директорию для перемещения архива');
            }


            echo json_encode(['newProductID' => $this->idProduct]);

        } else {
            throw new Exception('Не удалось открыть ZIP-архив.');
        }


    }


    // создание нового продукта, получение ID
    private function createProduct($pdf = null)
    {

        if (!$navId = $this->createNavigation()) return false;

        $query = "INSERT INTO `PROD_scripts` (
                      `ID_NAVIGATION`,
                      `PATH_SCRIPT`,
                      `UNIQ_NAME_FILE`,
                      `FORMAT`,
                      `LIBRARY_CODE`,
                      `TEST`,
                      `CREATE_DATETIME`
                      )
                    VALUES (
                      :ID_NAVIGATION,
                      :PATH_SCRIPT,
                      :UNIQ_NAME_FILE,
                      :FORMAT,
                      :LIBRARY_CODE,
                      :TEST,
                      :CREATE_DATETIME
                    )";

        if ($this->pathScript) {
            $pathScript = $this->pathScript . '/' . $this->installStaticMethod;
        } else {
            $pathScript = NULL;
        }

        $args = [
            'ID_NAVIGATION' => $navId, // create - название метода для генерации PDF
            'PATH_SCRIPT' => $pathScript, // create - название метода для генерации PDF
            'UNIQ_NAME_FILE' => $pdf==1?1:NULL, // уникальное имя файла, по умолчанию всегда уникальное
            'FORMAT' => $this->format,
            'LIBRARY_CODE' => $pdf==1?2:NULL, // dompdf
            'TEST' => 1, // 2 режим тестирования, только админам видно
            'CREATE_DATETIME' => date('Y-m-d H:i:s')
        ];

        DBase::sql($query, $args);

        if ($this->idProduct = DBase::lastInsertId()) {
            return $this->idProduct;
        }

        return false;
    }


    private function createNavigation()
    {
        $query = "INSERT INTO `navigation` (
                      `TITLE`,
                      `CODE_MENU`,
                      `PARENT`,
                      `FILE`,
                      `APP_METHOD`
                      )
                    VALUES (
                      :TITLE,
                      :CODE_MENU,
                      :PARENT,
                      :FILE,
                      :APP_METHOD
                    )";


        $code = substr(md5(time().rand(1000,9999)), -10);


        $args = [
            'TITLE' => $code, // create - название метода для генерации PDF
            'CODE_MENU' => $code, // уникальное имя файла, по умолчанию всегда уникальное
            'PARENT' => 45,
            'FILE' => 174, // dompdf
            'APP_METHOD' => 'NavCreateFiles/index'
        ];

        DBase::sql($query, $args);

        if ($newNavId = DBase::lastInsertId()) {
            return $newNavId;
        }

        return false;
    }


    // Добавление строк для продукта
    private function createFields($descriptionOfFields)
    {
        if (!$this->idProduct) {
            throw new Exception('Нет ID продукта');
        }

        $addArray = [];

        $sort = 1;

        foreach ($descriptionOfFields as $nameField => $param)
        {
            $addArray[$sort] = [
                'ID_PRODUCT' => $this->idProduct,
                'NAME_FIELD' => $nameField,
                'TITLE_LINE' => $param['line_name'],
                'SORT' => $sort,
                'OPTIONAL' => NULL,
                'VALUE_IN_SCRIPT' => NULL
            ];

            // если имеется необязательное поле, тогда установим его НЕОБЯЗАТЕЛЬНЫМ
            if (isset($param['optional']) AND $param['optional'] == 1) {
                $addArray[$sort]['OPTIONAL'] = 1;
                $addArray[$sort]['VALUE_IN_SCRIPT'] = 1;
            }

            $sort++;
        }

//        var_dump($addArray);
//        exit;

        // если добавилось все, тогда получим true, или false
        if (DBase::OnDuplicateKeyUpdate('PROD_valid_fields', $addArray, 1) === false) {
            return false;
        }

        return true;
    }



    # форматы файлов по ID: ['pdf'] => 1
    private function fileFormats()
    {
        $formats = DBase::getRows('SELECT `ID`, `EXP` FROM `file_formats`');

        foreach ($formats as $format) {
            $this->allFileFormats[$format['EXP']] = $format['ID'];
        }
    }


    // скачиваем файл в нужную директорию
    private function downloadFile($pathSaveFile, $url)
    {
        return file_put_contents($pathSaveFile, fopen($url, 'r'));
    }


    private function randomText($length = 14)
    {
        $permitted_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randomText = substr(str_shuffle($permitted_chars), 0, $length);
        return $randomText;
    }


    # Некоторые функции не поддерживают кириллицу. Эта функция изменит кириллицу на url encode
    private function encodeUrl($url) {
        $parts = parse_url($url);

        if (!$parts) return $url; // если parse_url не смог разобрать

        $scheme   = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
        $host     = $parts['host'] ?? '';
        $port     = isset($parts['port']) ? ':' . $parts['port'] : '';
        $user     = $parts['user'] ?? '';
        $pass     = isset($parts['pass']) ? ':' . $parts['pass']  : '';
        $pass     = ($user || $pass) ? "$pass@" : '';
        $path     = isset($parts['path']) ? implode('/', array_map('rawurlencode', explode('/', $parts['path']))) : '';
        $query    = isset($parts['query']) ? '?' . $parts['query'] : '';
        $fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';

        return "$scheme$user$pass$host$port$path$query$fragment";
    }
}