cgi.md
1> **Источник:** https://python-all.ru/3.12/library/cgi.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi) – поддержка Common Gateway Interface89**Исходный код:** [Lib/cgi.py](https://python-all.ru/src/3.12/Lib/cgi.py)1011Устарело с версии 3.11, будет удалено в версии 3.13: Модуль [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi) устарел (см. [**PEP 594**](https://python-all.ru/3.12/library/cgi.html) для получения подробностей и альтернатив).1213Класс `FieldStorage` обычно можно заменить на [`urllib.parse.parse_qsl()`](https://python-all.ru/3.12/library/urllib.parse.html#urllib.parse.parse_qsl) для запросов `GET` и `HEAD`, а для `POST` и `PUT` – модуль [`email.message`](https://python-all.ru/3.12/library/email.message.html#module-email.message) или [multipart](https://python-all.ru/3.12/library/cgi.html). Большинство [вспомогательных функций](https://python-all.ru/3.12/library/cgi.html#functions-in-cgi-module) имеют замены.1415---1617Вспомогательный модуль для скриптов Common Gateway Interface (CGI).1819Этот модуль определяет ряд утилит для использования CGI-скриптами, написанными на Python.2021Глобальная переменная `maxlen` может быть установлена в целое число, указывающее максимальный размер POST-запроса. POST-запросы размером больше этого значения приведут к возникновению исключения [`ValueError`](https://python-all.ru/3.12/library/exceptions.html#ValueError) во время разбора. Значение по умолчанию этой переменной – `0`, что означает неограниченный размер запроса.2223[Доступность](https://python-all.ru/3.12/library/intro.html#availability): not Emscripten, not WASI.2425Этот модуль не работает или недоступен на платформах WebAssembly `wasm32-emscripten` и `wasm32-wasi`. См. [платформы WebAssembly](https://python-all.ru/3.12/library/intro.html#wasm-availability) для получения дополнительной информации.2627## Введение2829CGI-скрипт вызывается HTTP-сервером, обычно для обработки пользовательского ввода, отправленного через элемент HTML `<FORM>` или `<ISINDEX>`.3031Чаще всего CGI-скрипты находятся в специальном каталоге сервера `cgi-bin`. HTTP-сервер помещает различную информацию о запросе (например, имя хоста клиента, запрошенный URL, строку запроса и множество других полезных данных) в окружение оболочки скрипта, выполняет скрипт и отправляет вывод скрипта обратно клиенту.3233Ввод скрипта также подключён к клиенту, и иногда данные формы читаются таким образом; в других случаях данные формы передаются через часть URL «строка запроса». Этот модуль предназначен для обработки различных ситуаций и предоставления более простого интерфейса для Python-скрипта. Он также предоставляет ряд утилит, помогающих при отладке скриптов, и последним дополнением является поддержка загрузки файлов из формы (если браузер это поддерживает).3435Вывод CGI-скрипта должен состоять из двух разделов, разделённых пустой строкой. Первый раздел содержит несколько заголовков, сообщающих клиенту, какие данные следуют. Код Python для генерации минимального раздела заголовков выглядит так:3637```python38print("Content-Type: text/html") # Далее HTML39print() # пустая строка, конец заголовков40```4142Второй раздел обычно представляет собой HTML, что позволяет клиентскому программному обеспечению отображать красиво отформатированный текст с заголовками, встроенными изображениями и т.д. Вот код Python, выводящий простой фрагмент HTML:4344```python45print("<TITLE>CGI script output</TITLE>")46print("<H1>This is my first CGI script</H1>")47print("Hello, world!")48```4950## Использование модуля cgi5152Начать следует с написания `import cgi`.5354При написании нового скрипта стоит добавить следующие строки:5556```python57import cgitb58cgitb.enable()59```6061Это активирует специальный обработчик исключений, который будет отображать подробные отчёты в веб-браузере при возникновении любых ошибок. Если не требуется показывать внутренности программы пользователям скрипта, можно сохранять отчёты в файлы с помощью такого кода:6263```python64import cgitb65cgitb.enable(display=0, logdir="/path/to/logdir")66```6768Очень полезно использовать эту возможность при разработке скрипта. Отчёты, создаваемые [`cgitb`](https://python-all.ru/3.12/library/cgitb.html#module-cgitb), предоставляют информацию, которая может сэкономить много времени при поиске ошибок. Строку `cgitb` можно удалить позже, когда скрипт будет протестирован и будет уверенность, что он работает правильно.6970Для доступа к отправленным данным формы используйте класс `FieldStorage`. Если форма содержит символы, не входящие в ASCII, задайте параметр *encoding*, указав кодировку, определённую для документа. Обычно она указывается в теге META в разделе HEAD HTML-документа или в заголовке *Content-Type*. Этот класс читает содержимое формы из стандартного ввода или окружения (в зависимости от значений различных переменных окружения, установленных согласно стандарту CGI). Поскольку он может потреблять стандартный ввод, его следует создавать только один раз.7172Экземпляр `FieldStorage` можно индексировать как словарь Python. Он позволяет проверять наличие ключей оператором [`in`](https://python-all.ru/3.12/reference/expressions.html#in), а также поддерживает стандартный метод словаря [`keys()`](https://python-all.ru/3.12/library/stdtypes.html#dict.keys) и встроенную функцию [`len()`](https://python-all.ru/3.12/library/functions.html#len). Поля формы, содержащие пустые строки, игнорируются и не появляются в словаре; чтобы сохранить такие значения, укажите истинное значение для необязательного именованного параметра *keep\_blank\_values* при создании экземпляра `FieldStorage`.7374Например, следующий код (предполагается, что заголовок *Content-Type* и пустая строка уже выведены) проверяет, что поля `name` и `addr` установлены в непустую строку:7576```python77form = cgi.FieldStorage()78if "name" not in form or "addr" not in form:79 print("<H1>Error</H1>")80 print("Please fill in the name and addr fields.")81 return82print("<p>name:", form["name"].value)83print("<p>addr:", form["addr"].value)84...further form processing here...85```8687Здесь поля, доступные через `form[key]`, сами являются экземплярами `FieldStorage` (или `MiniFieldStorage`, в зависимости от кодировки формы). Атрибут `value` экземпляра даёт строковое значение поля. Метод `getvalue()` возвращает это строковое значение напрямую; он также принимает необязательный второй аргумент – значение по умолчанию, возвращаемое, если запрошенный ключ отсутствует.8889Если отправленные данные формы содержат несколько полей с одинаковым именем, объект, полученный через `form[key]`, будет не экземпляром `FieldStorage` или `MiniFieldStorage`, а списком таких экземпляров. Аналогично в этой ситуации `form.getvalue(key)` вернёт список строк. Если предполагается такая возможность (когда HTML-форма содержит несколько полей с одинаковым именем), используйте метод [`getlist()`](https://python-all.ru/3.12/library/cgi.html#cgi.FieldStorage.getlist), который всегда возвращает список значений (чтобы не требовалось обрабатывать случай одного элемента отдельно). Например, следующий код объединяет любое количество полей с именами пользователей через запятую:9091```python92value = form.getlist("username")93usernames = ",".join(value)94```9596Если поле представляет загруженный файл, чтение значения через атрибут `value` или метод `getvalue()` загружает весь файл в память в виде байтов. Это может быть нежелательно. Можно проверить, является ли поле загруженным файлом, проверив атрибут `filename` или атрибут `file`. Затем можно прочитать данные из атрибута `file` до того, как он будет автоматически закрыт при сборке мусора экземпляра `FieldStorage` (методы [`read()`](https://python-all.ru/3.12/library/io.html#io.RawIOBase.read) и [`readline()`](https://python-all.ru/3.12/library/io.html#io.IOBase.readline) возвращают байты):9798```python99fileitem = form["userfile"]100if fileitem.file:101 # Это загруженный файл; подсчитать строки102 linecount = 0103 while True:104 line = fileitem.file.readline()105 if not line: break106 linecount = linecount + 1107```108109Объекты `FieldStorage` также поддерживают использование в операторе [`with`](https://python-all.ru/3.12/reference/compound_stmts.html#with), который автоматически закроет их по завершении.110111Если при получении содержимого загруженного файла возникает ошибка (например, пользователь прерывает отправку формы, нажав кнопку «Назад» или «Отмена»), атрибут `done` объекта поля будет установлен в значение -1.112113Проект стандарта загрузки файлов предусматривает возможность загрузки нескольких файлов из одного поля (с использованием рекурсивной кодировки *multipart/\**). В этом случае элемент будет представлять собой словареподобный элемент `FieldStorage`. Это можно определить, проверив его атрибут `type`, который должен быть равен *multipart/form-data* (или, возможно, другому MIME-типу, соответствующему *multipart/\**). В этом случае его можно рекурсивно перебирать так же, как объект формы верхнего уровня.114115Когда форма отправляется в «старом» формате (как строка запроса или как одна часть данных типа *application/x-www-form-urlencoded*), элементы на самом деле будут экземплярами класса `MiniFieldStorage`. В этом случае атрибуты `list`, `file` и `filename` всегда равны `None`.116117Форма, отправленная через POST и имеющая также строку запроса, будет содержать элементы как `FieldStorage`, так и `MiniFieldStorage`.118119Изменено в версии 3.4: Атрибут `file` автоматически закрывается при сборке мусора создавшего его экземпляра `FieldStorage`.120121Изменено в версии 3.5: Добавлена поддержка протокола управления контекстом для класса `FieldStorage`.122123## Интерфейс более высокого уровня124125В предыдущем разделе объясняется, как читать данные CGI-формы с помощью класса `FieldStorage`. В этом разделе описывается интерфейс более высокого уровня, который был добавлен в этот класс, чтобы позволить делать это более читабельным и интуитивным способом. Этот интерфейс не делает методы, описанные в предыдущих разделах, устаревшими – они по-прежнему полезны, например, для эффективной обработки загрузки файлов.126127Интерфейс состоит из двух простых методов. С их помощью можно обрабатывать данные формы универсально, не задумываясь о том, было ли отправлено одно или несколько значений под одним именем.128129В предыдущем разделе было показано, как писать следующий код каждый раз, когда ожидается, что пользователь отправит несколько значений под одним именем:130131```python132item = form.getvalue("item")133if isinstance(item, list):134 # Пользователь запрашивает более одного элемента.135else:136 # Пользователь запрашивает только один элемент.137```138139Такая ситуация часто возникает, например, когда форма содержит группу флажков с одинаковым именем:140141```python142<input type="checkbox" name="item" value="1" />143<input type="checkbox" name="item" value="2" />144```145146Однако в большинстве случаев в форме есть только один элемент управления с определённым именем, и тогда ожидается и требуется только одно значение, связанное с этим именем. Поэтому пишется скрипт, содержащий, например, такой код:147148```python149user = form.getvalue("user").upper()150```151152Проблема в том, что не следует рассчитывать, что клиент всегда будет передавать корректные данные в скрипты. Например, если любопытный пользователь добавит ещё одну пару `user=foo` в строку запроса, скрипт аварийно завершится, потому что в этом случае вызов метода `getvalue("user")` вернёт список вместо строки. Вызов метода [`upper()`](https://python-all.ru/3.12/library/stdtypes.html#str.upper) для списка недопустим (поскольку у списков нет метода с таким именем) и приводит к исключению [`AttributeError`](https://python-all.ru/3.12/library/exceptions.html#AttributeError).153154Поэтому единственным правильным способом чтения значений данных формы было всегда использовать код, проверяющий, является ли полученное значение одиночным или списком значений. Это утомительно и снижает читаемость скриптов.155156Более удобный подход – использовать методы [`getfirst()`](https://python-all.ru/3.12/library/cgi.html#cgi.FieldStorage.getfirst) и [`getlist()`](https://python-all.ru/3.12/library/cgi.html#cgi.FieldStorage.getlist), предоставляемые этим интерфейсом более высокого уровня.157158#### `FieldStorage.getfirst(name, default=None)`159160Этот метод всегда возвращает только одно значение, связанное с полем формы *name*. Метод возвращает только первое значение, если под этим именем было отправлено несколько значений. Обратите внимание, что порядок получения значений может различаться в разных браузерах, и полагаться на него не стоит. [\[1\]](https://python-all.ru/3.12/library/cgi.html#id3) Если такого поля формы или значения не существует, метод возвращает значение, указанное в необязательном параметре *default*. Этот параметр по умолчанию равен `None`, если не указан.161162#### `FieldStorage.getlist(name)`163164Этот метод всегда возвращает список значений, связанных с полем формы *name*. Метод возвращает пустой список, если для *name* не существует такого поля или значения. Возвращает список из одного элемента, если существует только одно значение.165166С помощью этих методов можно писать компактный код:167168```python169import cgi170form = cgi.FieldStorage()171user = form.getfirst("user", "").upper() # Так это безопасно.172for item in form.getlist("item"):173 do_something(item)174```175176## Функции177178Они полезны, если нужен более тонкий контроль или если требуется использовать некоторые алгоритмы, реализованные в этом модуле, в других ситуациях.179180#### `cgi.parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False, separator='&')`181182Разбирает запрос из окружения или из файла (по умолчанию файл – `sys.stdin`). Параметры *keep\_blank\_values*, *strict\_parsing* и *separator* передаются в [`urllib.parse.parse_qs()`](https://python-all.ru/3.12/library/urllib.parse.html#urllib.parse.parse_qs) без изменений.183184Устарело с версии 3.11, будет удалено в версии 3.13: Эта функция, как и весь модуль [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi), устарела. Её можно заменить прямым вызовом [`urllib.parse.parse_qs()`](https://python-all.ru/3.12/library/urllib.parse.html#urllib.parse.parse_qs) для нужной строки запроса (за исключением ввода `multipart/form-data`, который обрабатывается, как описано для [`parse_multipart()`](https://python-all.ru/3.12/library/cgi.html#cgi.parse_multipart)).185186#### `cgi.parse_multipart(fp, pdict, encoding='utf-8', errors='replace', separator='&')`187188Разбирает ввод типа *multipart/form-data* (для загрузки файлов). Аргументы: *fp* – входной файл, *pdict* – словарь, содержащий другие параметры в заголовке *Content-Type*, и *encoding* – кодировка запроса.189190Возвращает словарь, как и [`urllib.parse.parse_qs()`](https://python-all.ru/3.12/library/urllib.parse.html#urllib.parse.parse_qs): ключи – это имена полей, каждое значение – список значений для этого поля. Для не файловых полей значение – список строк.191192Этот подход прост в использовании, но не очень подходит, если ожидается загрузка мегабайт – в таком случае лучше использовать класс `FieldStorage`, который гораздо гибче.193194Изменено в версии 3.7: Добавлены параметры *encoding* и *errors*. Для не файловых полей значение теперь представляет собой список строк, а не байтов.195196Изменено в версии 3.10: Добавлен параметр *separator*.197198Устарело с версии 3.11, будет удалено в версии 3.13: Эта функция, как и весь модуль [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi), устарела. Её можно заменить функциональностью пакета [`email`](https://python-all.ru/3.12/library/email.html#module-email) (например, [`email.message.EmailMessage`](https://python-all.ru/3.12/library/email.message.html#email.message.EmailMessage)/[`email.message.Message`](https://python-all.ru/3.12/library/email.compat32-message.html#email.message.Message)), который реализует те же MIME RFC, или проектом [multipart](https://python-all.ru/3.12/library/cgi.html) на PyPI.199200#### `cgi.parse_header(string)`201202Разбирает MIME-заголовок (например, *Content-Type*) на основное значение и словарь параметров.203204Устарело с версии 3.11, будет удалено в версии 3.13: Эта функция, как и весь модуль [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi), устарела. Её можно заменить функциональностью пакета [`email`](https://python-all.ru/3.12/library/email.html#module-email), который реализует те же MIME RFC.205206Например, с помощью [`email.message.EmailMessage`](https://python-all.ru/3.12/library/email.message.html#email.message.EmailMessage):207208```python209from email.message import EmailMessage210msg = EmailMessage()211msg['content-type'] = 'application/json; charset="utf8"'212main, params = msg.get_content_type(), msg['content-type'].params213```214215#### `cgi.test()`216217Надёжный тестовый CGI-скрипт, который можно использовать как основную программу. Выводит минимальные HTTP-заголовки и форматирует всю переданную скрипту информацию в формате HTML.218219#### `cgi.print_environ()`220221Форматирует окружение оболочки в формате HTML.222223#### `cgi.print_form(form)`224225Форматирование формы в HTML.226227#### `cgi.print_directory()`228229Форматирование текущей директории в HTML.230231#### `cgi.print_environ_usage()`232233Вывод в HTML списка полезных переменных окружения (используемых CGI).234235## Забота о безопасности236237Есть одно важное правило: если вы запускаете внешнюю программу (через [`os.system()`](https://python-all.ru/3.12/library/os.html#os.system), [`os.popen()`](https://python-all.ru/3.12/library/os.html#os.popen) или другие функции с похожей функциональностью), убедитесь, что не передаёте оболочке произвольные строки, полученные от клиента. Это хорошо известная уязвимость, с помощью которой ловкие хакеры из любой точки сети могут заставить доверчивый CGI-скрипт выполнять произвольные команды оболочки. Даже части URL или имена полей нельзя считать безопасными – запрос не обязательно пришёл из вашей формы!238239Чтобы быть в безопасности, если вам всё же нужно передать строку из формы команде оболочки, стоит убедиться, что строка содержит только буквенно-цифровые символы, дефисы, символы подчёркивания и точки.240241## Установка CGI-скрипта в системе Unix242243Прочтите документацию вашего HTTP-сервера и уточните у местного системного администратора директорию, куда следует устанавливать CGI-скрипты; обычно это директория `cgi-bin` в дереве сервера.244245Убедитесь, что скрипт доступен для чтения и выполнения «другими»; файловая маска Unix должна быть `0o755` в восьмеричном виде (используйте `chmod 0755 filename`). Проверьте, что первая строка скрипта содержит `#!` начиная с первой позиции, за которым следует путь к интерпретатору Python, например:246247```python248#!/usr/local/bin/python249```250251Убедитесь, что интерпретатор Python существует и доступен для выполнения «другими».252253Убедитесь, что любые файлы, которые скрипт должен читать или писать, доступны для чтения или записи «другим» – их права должны быть `0o644` для чтения и `0o666` для записи. Это связано с тем, что из соображений безопасности HTTP-сервер выполняет скрипт от имени пользователя «nobody», без каких-либо особых привилегий. Он может только читать (писать, выполнять) файлы, которые доступны всем на чтение (запись, выполнение). Текущая директория во время выполнения тоже отличается (обычно это каталог cgi-bin сервера), и набор переменных окружения отличается от того, что получается при входе в систему. В частности, не рассчитывайте, что путь поиска исполняемых файлов оболочки (`PATH`) или путь поиска модулей Python ([`PYTHONPATH`](https://python-all.ru/3.12/using/cmdline.html#envvar-PYTHONPATH)) будут установлены во что-то содержательное.254255Если вам нужно загружать модули из директории, которой нет в пути поиска модулей Python по умолчанию, можно изменить путь в скрипте перед импортом других модулей. Например:256257```python258import sys259sys.path.insert(0, "/usr/home/joe/lib/python")260sys.path.insert(0, "/usr/local/lib/python")261```262263(Так директория, вставленная последней, будет просматриваться первой!)264265Инструкции для систем, отличных от Unix, различаются; ознакомьтесь с документацией вашего HTTP-сервера (обычно в ней есть раздел о CGI-скриптах).266267## Тестирование CGI-скрипта268269К сожалению, CGI-скрипт обычно не работает при запуске из командной строки, а скрипт, отлично работающий в командной строке, может таинственно отказываться при запуске через сервер. Но есть одна причина, по которой всё же стоит тестировать скрипт из командной строки: если в нём есть синтаксическая ошибка, интерпретатор Python вообще не выполнит его, и HTTP-сервер, скорее всего, отправит клиенту малопонятную ошибку.270271Если в скрипте нет синтаксических ошибок, но он всё равно не работает, ничего не остаётся, кроме как прочитать следующий раздел.272273## Отладка CGI-скриптов274275Прежде всего, проверьте наличие тривиальных ошибок установки – внимательное чтение раздела об установке CGI-скрипта выше может сэкономить много времени. Если вы сомневаетесь, правильно ли поняли процедуру установки, попробуйте установить копию этого файла модуля (`cgi.py`) в качестве CGI-скрипта. При вызове как скрипта этот файл выведет своё окружение и содержимое формы в формате HTML. Задайте правильные права и т.д., а затем отправьте ему запрос. Если он установлен в стандартную директорию `cgi-bin`, должно быть возможно отправить запрос, введя в браузере URL следующего вида:276277```text278http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home279```280281Если это даёт ошибку типа 404, сервер не может найти скрипт – возможно, нужно установить его в другую директорию. Если возникает другая ошибка, значит есть проблема с установкой, которую нужно исправить, прежде чем продолжать. Если вы получаете аккуратно отформатированный список окружения и содержимого формы (в этом примере поля должны отображаться как «addr» со значением «At Home» и «name» со значением «Joe Blow»), значит скрипт `cgi.py` установлен правильно. Если повторить ту же процедуру для вашего собственного скрипта, теперь вы сможете его отлаживать.282283Следующим шагом может быть вызов функции [`test()`](https://python-all.ru/3.12/library/test.html#module-test) модуля [`cgi`](https://python-all.ru/3.12/library/cgi.html#module-cgi) из вашего скрипта: замените его основной код единственным оператором284285```python286cgi.test()287```288289Это должно дать те же результаты, что и при установке самого файла `cgi.py`.290291Когда обычный скрипт Python вызывает необработанное исключение (по любой причине: опечатка в имени модуля, файл, который не удаётся открыть, и т.п.), интерпретатор Python печатает подробную трассировку и завершает работу. Хотя интерпретатор Python всё ещё делает это, когда ваш CGI-скрипт вызывает исключение, скорее всего, трассировка попадёт в один из журнальных файлов HTTP-сервера или вообще будет отброшена.292293К счастью, когда вам удалось заставить скрипт выполнить *хоть какой-то* код, вы можете легко отправлять трассировки в веб-браузер с помощью модуля [`cgitb`](https://python-all.ru/3.12/library/cgitb.html#module-cgitb). Если вы ещё этого не сделали, просто добавьте строки:294295```python296import cgitb297cgitb.enable()298```299300в начало скрипта. Затем попробуйте запустить его снова; при возникновении проблемы вы увидите подробный отчёт, который, вероятно, укажет на причину сбоя.301302Если вы подозреваете, что может быть проблема с импортом модуля [`cgitb`](https://python-all.ru/3.12/library/cgitb.html#module-cgitb), можно использовать ещё более надёжный подход (использующий только встроенные модули):303304```python305import sys306sys.stderr = sys.stdout307print("Content-Type: text/plain")308print()309...your code here...310```311312Этот подход полагается на интерпретатор Python для печати трассировки. Тип содержимого вывода устанавливается в обычный текст, что отключает всю обработку HTML. Если ваш скрипт работает, сырой HTML будет отображён клиентом. Если он вызывает исключение, скорее всего, после вывода первых двух строк будет показана трассировка. Поскольку интерпретация HTML не происходит, трассировка будет читаемой.313314## Частые проблемы и их решения315316- Большинство HTTP-серверов буферизуют вывод CGI-скриптов до завершения скрипта. Это означает, что невозможно отображать индикатор выполнения на экране клиента во время работы скрипта.317- Проверьте инструкции по установке выше.318- Проверьте файлы журнала HTTP-сервера. (`tail -f logfile` в отдельном окне может оказаться полезным!)319- Всегда сначала проверяйте скрипт на синтаксические ошибки, выполнив что-то вроде `python script.py`.320- Если в скрипте нет синтаксических ошибок, попробуйте добавить `import cgitb; cgitb.enable()` в начало скрипта.321- При вызове внешних программ убедитесь, что они могут быть найдены. Обычно это означает использование абсолютных путей – `PATH` обычно не содержит полезного значения в CGI-скрипте.322- При чтении или записи внешних файлов убедитесь, что они могут быть прочитаны или записаны идентификатором пользователя (userid), от имени которого будет выполняться CGI-скрипт: обычно это идентификатор пользователя, под которым работает веб-сервер, или явно указанный идентификатор для функции `suexec` веб-сервера.323- Не пытайтесь установить CGI-скрипту режим set-uid. На большинстве систем это не работает и к тому же создаёт угрозу безопасности.324325Сноски326327\[[1](https://python-all.ru/3.12/library/cgi.html#id2)\]328329Обратите внимание, что некоторые последние версии спецификации HTML действительно определяют порядок, в котором должны передаваться значения полей, но определение того, был ли запрос получен от соответствующего спецификации браузера, или вообще от браузера, – задача утомительная и чреватая ошибками.330