Файл jsmin.php в Cotonti CMF

Файл jsmin.php в Cotonti CMF реализует PHP-версию библиотеки для минификации JavaScript-кода, которая является портом известного инструмента jsmin.c от Douglas Crockford, адаптированного для PHP. Этот файл служит для сжатия и оптимизации JavaScript-кода, удаляя ненужные пробелы, комментарии и другие избыточности, улучшая таким образом производительность веб-приложений, снижая время загрузки и ускоряя выполнение JavaScript в браузере.

Основное назначение:

Цель данного файла — минимизация (минификация) JavaScript-кода. Это процесс удаления лишних пробелов, комментариев, строк, не влияющих на работу программы, с целью уменьшения объема кода и ускорения его загрузки и выполнения в браузере. Этот процесс играет важную роль в веб-разработке, особенно для крупных проектов с большим количеством JavaScript-кода.

Место в системе Cotonti:

Файл находится в каталоге /lib/, что означает, что он представляет собой вспомогательную библиотеку, которая используется для минификации файлов JavaScript перед их отправкой в браузер клиента. Он может быть использован в рамках обработки и оптимизации файлов на серверной стороне перед их выводом пользователю или сохранением для дальнейшего использования.

Методы, функции и классы:

  1. Класс JSMin: Класс JSMin является основным элементом, который инкапсулирует логику минификации. Он содержит все необходимые функции для обработки и сжатия JavaScript-кода. Основной метод — это min(), который выполняет процесс минификации, принимая исходный JavaScript-код в виде строки и возвращая его оптимизированную версию.

  2. Метод minify(): Это публичный статический метод, который инициализирует объект класса JSMin с переданным JavaScript-кодом и вызывает метод min() для выполнения минификации. Результат возвращается как сжатая версия исходного кода.

  3. Методы работы с символами и строками:

    • get(): Извлекает следующий символ из строки, обрабатывая специальные случаи, такие как замена символа возврата каретки на новую строку и игнорирование символов, которые не важны для минификации.
    • next(): Обрабатывает комментарии (как однострочные, так и многострочные), и, если встречается комментарий, игнорирует его, возвращая следующий значимый символ.
    • peek(): Используется для просмотра следующего символа без его извлечения, что полезно для обработки комментариев и регулярных выражений.
    • action(): Основной метод, который выполняет разные действия в зависимости от текущего состояния и символов в потоке. В нем реализована логика обработки пробелов, новых строк, строковых литералов и регулярных выражений.
    • isAlphaNum(): Проверяет, является ли символ буквой, цифрой, подчеркиванием или символом доллара. Это необходимо для правильной обработки идентификаторов и переменных в JavaScript.
  4. Обработка ошибок: Для обработки ошибок используется класс JSMinException, который наследует стандартный класс исключений PHP. Это позволяет генерировать и ловить исключения в случае возникновения ошибок, таких как незавершенные строковые литералы или регулярные выражения.

Суть содержания кода:

Код включает несколько ключевых этапов для выполнения минификации:

  1. Чтение и обработка символов: Код обрабатывает входной JavaScript, анализируя его символы по одному, игнорируя лишние пробелы, символы новой строки и комментарии.
  2. Обработка строк и регулярных выражений: Строковые литералы и регулярные выражения обрабатываются отдельно, чтобы избежать их случайного удаления в процессе минификации.
  3. Удаление ненужных пробелов и комментариев: Пробелы, табуляции и комментарии, которые не влияют на выполнение кода, удаляются для уменьшения размера файла.
  4. Оптимизация кода: Строки, разделяющие элементы JavaScript (такие как запятые и точки с запятой), приводятся к единому виду без лишних пробелов, что уменьшает общий размер кода.

Задачи и условия, которые выполняет код:

  • Минификация JavaScript-кода: Главная задача файла — обработать JavaScript и вернуть его в минимизированном виде, что снижает объем передаваемых данных.
  • Оптимизация загрузки страниц: Сокращение размера скриптов улучшает скорость загрузки страниц, что является важным аспектом для повышения производительности веб-приложений.
  • Обработка различных синтаксических конструкций JavaScript: Код корректно обрабатывает строки, регулярные выражения и комментарии, чтобы они не влияли на минификацию. Это гарантирует, что функциональность кода сохраняется при его сжатии.

Заключение:

Файл jsmin.php является важным инструментом для разработки в Cotonti, предоставляя возможности для автоматической минификации JavaScript-кода. Это улучшает производительность веб-сайтов или приложений, снижая время загрузки и оптимизируя работу JavaScript на клиентской стороне.

 

/**
 * jsmin.php - PHP реализация JSMin от Douglas Crockford.
 *
 * Это практически прямой порт jsmin.c на PHP с небольшими
 * оптимизациями для PHP. В отличие от jsmin.c, который читает из stdin и
 * выводит в stdout, эта библиотека принимает строку в качестве входных данных
 * и возвращает другую строку в качестве выходных данных.
 *
 * Требуется PHP 5 или выше.
 *
 * Разрешается использовать эту версию библиотеки на тех же условиях, что и jsmin.c,
 * который имеет следующую лицензию:
 *
 *
 * @package JSMin  // Указывает, что этот код относится к пакету JSMin.
 * @author Ryan Grove <[email protected]>  // Автор порта на PHP.
 * @copyright 2002 Douglas Crockford <[email protected]> (jsmin.c) // Оригинальный автор jsmin.c.
 * @copyright 2008 Ryan Grove <[email protected]> (PHP port) // Автор PHP-версии.
 * @license http://opensource.org/licenses/mit-license.php MIT License // Указывает на лицензию MIT.
 * @version 1.1.1 (2008-03-02) // Версия и дата последнего обновления.
 * @link https://github.com/rgrove/jsmin-php/ // Ссылка на репозиторий.
 */

class JSMin { // Объявление класса JSMin, который выполняет минификацию JavaScript-кода.
  const ORD_LF    = 10;   // Константа, обозначающая ASCII-код символа перевода строки (LF).
  const ORD_SPACE = 32;   // Константа, обозначающая ASCII-код пробела.

 

  protected $a           = '';  // Текущий символ, обрабатываемый в коде.
  protected $b           = '';  // Следующий значимый символ в коде.
  protected $input       = '';  // Исходный JavaScript-код, переданный для минификации.
  protected $inputIndex  = 0;   // Текущая позиция (индекс) в строке кода.
  protected $inputLength = 0;   // Общая длина переданного JavaScript-кода.
  protected $lookAhead   = null; // Предварительно загруженный символ (если есть).
  protected $output      = '';  // Минифицированный (сжатый) JavaScript-код.

  // -- Общедоступные статические методы ---------------------------------------

  public static function minify($js) { // Статический метод для упрощенного вызова минификации.
    $jsmin = new JSMin($js); // Создаёт новый экземпляр JSMin с переданным JavaScript-кодом.
    return $jsmin->min(); // Вызывает метод min(), который выполняет минификацию и возвращает результат.
  }

  // -- Общедоступные методы экземпляра ----------------------------------------

  public function __construct($input) { // Конструктор класса, принимает строку JavaScript-кода.
    $this->input       = str_replace("\r\n", "\n", $input); // Преобразует символы переноса строк из формата Windows в Unix.
    $this->inputLength = strlen($this->input); // Определяет и сохраняет длину входного JavaScript-кода.
  }

 

  // -- Защищённые методы экземпляра --------------------------------------------

  /* action — выполняет одно из трёх действий в зависимости от аргумента:
          1   Выводит `a`. Копирует `b` в `a`. Получает следующий `b`.
          2   Копирует `b` в `a`. Получает следующий `b` (удаляет `a`).
          3   Получает следующий `b` (удаляет `b`).
     action воспринимает строку как одиночный символ.
     action распознаёт регулярное выражение, если перед ним стоит ( или , или =.
  */
  protected function action($d) { // Метод выполняет одно из трёх действий в зависимости от переданного параметра.
    switch($d) { // Определяет, какой случай обработки выполнять.
      case 1: // Если $d равно 1.
        $this->output .= $this->a; // Добавляет текущий символ `a` в выходной код.

      case 2: // Если $d равно 2.
        $this->a = $this->b; // Переносит `b` в `a`.

        if ($this->a === "'" || $this->a === '"') { // Если `a` является кавычкой (начало строкового литерала).
          for (;;) { // Бесконечный цикл обработки строки.
            $this->output .= $this->a; // Добавляет `a` в выходной код.
            $this->a       = $this->get(); // Получает следующий символ.

            if ($this->a === $this->b) { // Если встретилась закрывающая кавычка, выходит из цикла.
              break; // Прерывает цикл.
            }

            if (ord($this->a) <= self::ORD_LF) { // Проверяет, не является ли символ управляющим символом новой строки.
              throw new JSMinException('Незавершённый строковый литерал.'); // Вызывает исключение, если строка не завершена.
            }

            if ($this->a === '\\') { // Если встретился символ экранирования.
              $this->output .= $this->a; // Добавляет `\` в выходной код.
              $this->a       = $this->get(); // Получает следующий символ после `\`.
            }
          }
        }

      case 3: // Если $d равно 3.
        $this->b = $this->next(); // Получает следующий символ в `b`.

        if ($this->b === '/' && ( // Проверяет, начинается ли `b` с `/` и является ли это началом регулярного выражения.
            $this->a === '(' || $this->a === ',' || $this->a === '=' ||
            $this->a === ':' || $this->a === '[' || $this->a === '!' ||
            $this->a === '&' || $this->a === '|' || $this->a === '?' ||
            $this->a === '{' || $this->a === '}' || $this->a === ';' ||
            $this->a === "\n" )) { // Если перед `/` стоит один из перечисленных символов, значит, это регулярное выражение.

          $this->output .= $this->a . $this->b; // Добавляет `a` и `b` (`/`) в выходной код.

          for (;;) { // Бесконечный цикл обработки регулярного выражения.
            $this->a = $this->get(); // Получает следующий символ.

            if ($this->a === '[') { // Если встретилась открывающая `[` внутри регулярного выражения.
              for (;;) { // Цикл обработки набора символов внутри `[...]`.
                $this->output .= $this->a; // Добавляет `a` в выходной код.
                $this->a = $this->get(); // Получает следующий символ.

                if ($this->a === ']') { // Если встретилась закрывающая `]`, выход из цикла.
                    break; // Прерывает цикл.
                } elseif ($this->a === '\\') { // Если встретился `\`, обрабатывает экранированный символ.
                  $this->output .= $this->a; // Добавляет `\` в выходной код.
                  $this->a       = $this->get(); // Получает следующий символ после `\`.
                } elseif (ord($this->a) <= self::ORD_LF) { // Если достигнут конец строки без закрытия `]`.
                  throw new JSMinException('Незавершённый набор символов в регулярном выражении.'); // Вызывает исключение.
                }
              }
            } elseif ($this->a === '/') { // Если встретилась закрывающая `/`, завершает регулярное выражение.
              break; // Прерывает цикл.
            } elseif ($this->a === '\\') { // Если встретился `\`, обрабатывает экранированный символ.
              $this->output .= $this->a; // Добавляет `\` в выходной код.
              $this->a       = $this->get(); // Получает следующий символ после `\`.
            } elseif (ord($this->a) <= self::ORD_LF) { // Если достигнут конец строки без закрытия `/`.
              throw new JSMinException('Незавершённое регулярное выражение.'); // Вызывает исключение.
            }

            $this->output .= $this->a; // Добавляет текущий символ `a` в выходной код.
          }

          $this->b = $this->next(); // Получает следующий символ после завершения обработки регулярного выражения.
        }
    }
  }

 

  protected function get() { // Метод для получения следующего символа из входных данных.
    $c = $this->lookAhead; // Сохраняет значение предварительного просмотра символа в переменную `$c`.
    $this->lookAhead = null; // Обнуляет предварительный просмотр символа.

    if ($c === null) { // Если нет символа для предварительного просмотра (переменная `$c` пуста),
      if ($this->inputIndex < $this->inputLength) { // и если индекс ещё не достиг конца строки,
        $c = substr($this->input, $this->inputIndex, 1); // получает следующий символ из строки.
        $this->inputIndex += 1; // Увеличивает индекс, чтобы двигаться к следующему символу.
      } else { // Если достигнут конец строки,
        $c = null; // устанавливает `$c` в `null`, что означает конец ввода.
      }
    }

    if ($c === "\r") { // Если символ — это возврат каретки (Carriage Return),
      return "\n"; // возвращает символ новой строки (перевод строки), заменяя `\r` на `\n`.
    }

    if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { // Если символ — это конец строки, `null`, или пробельный символ,
      return $c; // возвращает его без изменений.
    }

    return ' '; // В любом другом случае заменяет символ на пробел.
  }

 

  /* isAlphanum -- возвращает true, если символ является буквой, цифрой, подчеркиванием,
        знаком доллара или не-ASCII символом.
  */
  protected function isAlphaNum($c) { // Метод проверяет, является ли символ алфавитным или числовым.
    if ($c === null || $c === false) { // Если символ равен null или false,
        return false; // возвращает false.
    }
    return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; // Если код символа больше 126 (не-ASCII символ), либо символ — это обратный слэш, либо символ является буквенно-цифровым или знаком доллара (проверяется с помощью регулярного выражения), возвращает true. В противном случае — false.
  }

 

  protected function min() { // Метод min() — основной процесс минификации.
    $this->a = "\n"; // Инициализация переменной $a значением новой строки, начинается с символа новой строки.
    $this->action(3); // Вызов метода action с аргументом 3, для выполнения действия с первым символом (инициализация).

    while ($this->a !== null) { // Цикл продолжается до тех пор, пока переменная $a не станет null.
      switch ($this->a) { // Проверка значения переменной $a, в зависимости от которого выполняется соответствующее действие.
        case ' ': // Если $a является пробелом,
          if ($this->isAlphaNum($this->b)) { // Если переменная $b является буквенно-цифровым символом,
            $this->action(1); // Выполнить действие 1, что значит добавить символ $a в вывод и передвинуть указатель.
          } else {
            $this->action(2); // В противном случае выполнить действие 2, что значит пропустить пробел.
          }
          break; // Выход из блока case пробела.

        case "\n": // Если $a является новой строкой,
          switch ($this->b) { // Проверка значения переменной $b, чтобы определить, как поступить с новой строкой.
            case '{': // Если $b — символ открывающей фигурной скобки,
            case '[': // или открывающей квадратной скобки,
            case '(': // или открывающей круглой скобки,
            case '+': // или знака плюса,
            case '-': // или знака минуса,
              $this->action(1); // Выполняем действие 1, то есть сохраняем $a и продолжаем обработку, добавляем в вывод.
              break; // Выход из блока case новой строки.

            case ' ': // Если $b — пробел,
              $this->action(3); // Выполняем действие 3, что означает просто пропуск пробела.
              break;

            default: // Если ни одно из предыдущих условий не выполнено,
              if ($this->isAlphaNum($this->b)) { // Если $b является буквенно-цифровым символом,
                $this->action(1); // Выполняем действие 1, добавляем $a в вывод.
              }
              else {
                $this->action(2); // В противном случае выполняем действие 2, пропускаем символ.
              }
          }
          break;

        default: // Если $a не является пробелом или новой строкой,
          switch ($this->b) { // Проверяем значение $b.
            case ' ': // Если $b — пробел,
              if ($this->isAlphaNum($this->a)) { // Если $a является буквенно-цифровым символом,
                $this->action(1); // Выполняем действие 1, добавляем символ $a в вывод.
                break;
              }

              $this->action(3); // Если $a не буквенно-цифровой символ, выполняем действие 3, пропускаем пробел.
              break;

            case "\n": // Если $b — новая строка,
              switch ($this->a) { // Проверяем значение $a.
                case '}': // Если $a — закрывающая фигурная скобка,
                case ']': // или закрывающая квадратная скобка,
                case ')': // или закрывающая круглая скобка,
                case '+': // или знак плюса,
                case '-': // или знак минуса,
                case '"': // или кавычка,
                case "'": // или апостроф,
                  $this->action(1); // Выполняем действие 1, добавляем символ $a в вывод.
                  break;

                default: // Если $a не соответствует ни одному из перечисленных случаев,
                  if ($this->isAlphaNum($this->a)) { // Если $a — буквенно-цифровой символ,
                    $this->action(1); // Выполняем действие 1, добавляем $a в вывод.
                  }
                  else {
                    $this->action(3); // В противном случае выполняем действие 3, пропускаем символ.
                  }
              }
              break;

            default: // Если $b не является пробелом или новой строкой,
              $this->action(1); // Выполняем действие 1, добавляем символ в вывод.
              break;
          }
      }
    }

    return $this->output; // Возвращаем результат минификации в виде строки.
  }

Объяснение:

  1. Основная цель метода min(): Минификация входного JavaScript-кода, удаляя лишние пробелы, переносы строк и ненужные символы. Это выполняется через несколько уровней вложенных условий, которые проверяют символы и в зависимости от контекста (например, пробел или новая строка) выполняется соответствующее действие.

  2. Цикл и проверка символов: Цикл while продолжается до тех пор, пока не обрабатываются все символы во входной строке, причем каждая итерация проверяет текущий символ и определяет, нужно ли его добавить в вывод, пропустить или выполнить другое действие.

  3. Использование метода action(): Этот метод обрабатывает различные действия в зависимости от текущего контекста (например, добавление символа в результат или его пропуск).

  4. Действия с символами: В коде рассматриваются различные случаи для пробела, новой строки и других символов. В каждом случае определяется, нужно ли продолжать минификацию или пропустить символ (например, если символ — пробел, то решение зависит от того, следует ли оставить его или удалить).

Метод использует проверку условий для адаптации минификации под разные контексты в коде, чтобы результат был корректным и эффективно минифицированным JavaScript-кодом.

 

  /* next -- get the next character, excluding comments. peek() is used to see
             if a '/' is followed by a '/' or '*'.
  */
  protected function next() { // Метод next() — получает следующий символ, исключая комментарии.
    $c = $this->get(); // Получаем следующий символ с помощью метода get(), который учитывает предыдущие символы.

    if ($c === '/') { // Если символ равен слэшу ("/"),
      switch($this->peek()) { // Проверяем следующий символ с помощью peek(), чтобы выяснить, что следует за "/".
        case '/': // Если следующий символ — слэш (начало однострочного комментария),
          for (;;) { // Запускаем бесконечный цикл для пропуска содержимого комментария.
            $c = (string) $this->get(); // Получаем следующий символ.

            if (ord($c) <= self::ORD_LF) { // Если символ — это символ новой строки или меньше (по значению),
              return $c; // Возвращаем символ новой строки, завершая комментарий.
            }
          }

        case '*': // Если следующий символ — звездочка (начало многострочного комментария),
          $this->get(); // Пропускаем звездочку.

          for (;;) { // Запускаем бесконечный цикл для пропуска содержимого многострочного комментария.
            switch($this->get()) { // Получаем следующий символ и проверяем его.
              case '*': // Если символ — звездочка,
                if ($this->peek() === '/') { // И следующий символ — слэш (закрывающая часть комментария),
                  $this->get(); // Пропускаем слэш.
                  return ' '; // Возвращаем пробел, что означает завершение комментария.
                }
                break;

              case null: // Если символ равен null (конец ввода),
                throw new JSMinException('Unterminated comment.'); // Бросаем исключение, так как комментарий не завершен.
            }
          }

        default: // Если следующий символ не является ни слэшем, ни звездочкой,
          return $c; // Возвращаем символ без изменений.
      }
    }

    return $c; // Если символ не является слэшем, просто возвращаем его.
  }

  protected function peek() { // Метод peek() — смотрит на следующий символ, не изменяя текущего положения указателя.
    $this->lookAhead = $this->get(); // Получаем следующий символ и сохраняем его в переменную lookAhead.
    return $this->lookAhead; // Возвращаем символ, который будет использоваться для дальнейшей проверки.
  }

Объяснение:

  1. Метод next(): Этот метод получает следующий символ, игнорируя комментарии (как однострочные, так и многострочные). Если встречается комментарий, метод пропускает его содержимое и продолжает обработку.

  2. Обработка однострочных комментариев (//): Когда встречается символ /, метод использует peek() для проверки следующего символа. Если это второй /, это означает начало однострочного комментария, и метод будет продолжать считывать символы, пока не встретит символ новой строки.

  3. Обработка многострочных комментариев (/* */): Когда встречается символ /, метод проверяет, не является ли следующий символ звездочкой (*), что указывает на начало многострочного комментария. В таком случае метод пропускает все символы внутри комментария, пока не встретит закрывающую звездочку и слэш (*/).

  4. Метод peek(): Этот метод используется для просмотра следующего символа, не двигая указатель на ввод, что позволяет проверить, что идет после текущего символа. Этот метод важен для определения типа комментария (однострочный или многострочный).

 

// -- Exceptions ---------------------------------------------------------------
class JSMinException extends Exception {} // Создаем класс исключения JSMinException, который наследует стандартное исключение PHP (Exception).

Объяснение:

  • Этот фрагмент кода объявляет класс JSMinException, который расширяет стандартное исключение Exception в PHP. Класс не добавляет дополнительной логики или свойств, но он позволяет создавать специфические исключения для обработки ошибок в процессе минификации JavaScript.
  • Использование этого класса позволяет идентифицировать ошибки, связанные с минификатором JS, как отдельные исключения, которые можно обрабатывать отдельно от других типов ошибок в программе.

 

 

 

 

 

15 minutes read Sodium Carbonate

Comments (0)

No comments yet
Only registered users can post new comments

Content author

webitproff

Offline

Sodium Carbonate

Last logged: 2026-09-03 18:32

About me briefly
Support and development of web projects on the CMF Cotonti: private messengers via the website, open and closed small social networks, trading platforms and marketplaces, freelance and services exchange portal, catalogs of goods from wholesale suppliers, dropshipping platforms, online stores, and much more.
View developments and download
Public portfolio of my works and developments
Telegram for messages
@webitproff
Telegram channel
@s/aBuyFILE
  • Page published: 2025-01-30 16:32
  • Last update: 2025-01-30 16:45

Similar pages

Файл DetectLostConnectionTrait.php в Cotonti CMF
1 Файл DetectLostConnectionTrait.php в движке Cotonti CMF реализует трейд, который содержит методы для обнаружения потери
Файл BaseController.php в Cotonti CMF
2 Назначение класса BaseController в Cotonti CMF Класс BaseController является базовым контроллером в системе Cotonti
Файл BaseAction.php в Cotonti CMF
3 Назначение класса BaseAction в Cotonti CMF: Класс BaseAction представляет собой абстрактный базовый класс, служащий
Файл IndexAction.php в Cotonti CMF
4 Назначение и описание класса IndexAction в Cotonti Основное назначение файла и его место в системе Файл
Файл admin.cache.disk.php в Cotonti CMF
5 Файл admin.cache.disk.php в движке Cotonti CMF является частью административной панели, предназначенной для управления