<MyRusakov.ru />

Программирование на C++ в Unreal Engine 5

Программирование на C++ в Unreal Engine 5

Данный курс научит Вас созданию игр на C++ в Unreal Engine 5. Курс состоит из 12 разделов, в которых Вас ждёт теория и практика. Причём, в качестве практики будет создан весьма крупный проект объёмом свыше 5000 строк качественного кода, который уже на практике познакомит Вас с принципами создания игр на C++ в Unreal Engine 5.

Параллельно с курсом Вы также будете получать домашние задания, результатом которых станет, в том числе, полноценная серьёзная работа для портфолио.

Помимо самого курса Вас ждёт ещё и очень ценный Бонус: «Тестирование Unreal-проектов на Python», в рамках которого Вы научитесь писать очень полезные тесты для тестирования самых разных аспектов разработки игр.

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

PHP header(): HTTP‑заголовки, редирект и кеширование — практическое руководство

PHP header(): HTTP‑заголовки, редирект и кеширование — практическое руководство

Функция header() — один из базовых инструментов PHP для управления ответом сервера. С её помощью вы задаёте Content-Type, выполняете редиректы, настраиваете кеширование, CORS и даже раздачу файлов. В статье — практичные паттерны и готовые сниппеты, чтобы быстро решать повседневные задачи и избегать подводных камней.

Когда отправляются заголовки и откуда берётся «Headers already sent»

Заголовки уходят клиенту до первого байта тела ответа. Если вы что-то выводили (echo, var_dump, HTML) — менять заголовки уже нельзя. Проверить можно так:

<?php
if (headers_sent($file, $line)) {
    error_log("Заголовки уже отправлены в $file:$line");
}

Частые причины ошибки:

  • Пробелы или переносы строк до <?php или после ?>
  • BOM в файлах (UTF‑8 without BOM обязателен)
  • Ранняя отладочная печать

На время разработки можно включить буферизацию как «подушку безопасности», но лучше дисциплинировать вывод:

<?php
ob_start(); // Стартуем как можно раньше
// ... ваш код
ob_end_flush();

Синтаксис header() и установка статуса

Базовые примеры отправки заголовков и статуса ответа:

<?php
header('Content-Type: application/json; charset=UTF-8');
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');

// Редирект со статусом
header('Location: /login', true, 302);
exit; // Завершаем скрипт после редиректа

// Либо отдельно код:
http_response_code(404);
echo json_encode(['error' => 'Not found']);

Аргумент replace (второй) позволяет не перезаписывать уже установленный одноимённый заголовок: header('Cache-Control: max-age=60', false);

Редиректы правильно: 301/302/303/307/308 и PRG-паттерн

  • 301 — постоянный редирект (SEO, кэшируется браузером).
  • 302 — временный (по умолчанию в PHP).
  • 303 — после POST перенаправляет на GET (PRG-паттерн).
  • 307/308 — сохраняют метод (307 временный, 308 постоянный).
<?php
// Пример PRG после успешного логина
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $ok = login($_POST['email'] ?? '', $_POST['pass'] ?? '');
    if ($ok) {
        header('Location: /dashboard', true, 303); // POST -> GET
        exit;
    }
}
// Показываем форму логина (GET)

JSON API: Content-Type, статус и кеш одним хелпером

<?php
function sendJson($data, int $status = 200, int $cacheTtl = 0): void {
    header('Content-Type: application/json; charset=UTF-8');
    http_response_code($status);

    if ($cacheTtl > 0) {
        header('Cache-Control: public, max-age=' . $cacheTtl);
    } else {
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Pragma: no-cache');
    }

    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

// Использование
sendJson(['ok' => true, 'items' => [1,2,3]], 200, 60);

Кеширование: Cache-Control, ETag и Last-Modified

Для динамики хватит Cache-Control. Для тонкой валидации — ETag и Last-Modified с поддержкой условных запросов.

<?php
$content = render_article($id);
$etag = 'W/"' . md5($content) . '"';
$lastModified = gmdate('D, d M Y H:i:s', filemtime(article_path($id))) . ' GMT';

header('ETag: ' . $etag);
header('Last-Modified: ' . $lastModified);
header('Cache-Control: public, max-age=300');

$ifNoneMatch = $_SERVER['HTTP_IF_NONE_MATCH'] ?? '';
$ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? '';

if ($ifNoneMatch === $etag || $ifModifiedSince === $lastModified) {
    http_response_code(304); // Not Modified
    exit;
}

echo $content;

Раздача файлов: Content-Disposition и безопасность

<?php
$file = __DIR__ . '/reports/2026.pdf';
if (!is_file($file)) {
    http_response_code(404);
    exit('File not found');
}

header('Content-Type: application/pdf');
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename="report-2026.pdf"');
header('X-Content-Type-Options: nosniff');

readfile($file);
exit;

Никогда не подставляйте имена файлов напрямую из пользовательского ввода без проверки пути и белых списков расширений.

Базовый CORS для простых сценариев

<?php
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowed = ['https://app.example.com'];
if (in_array($origin, $allowed, true)) {
    header('Access-Control-Allow-Origin: ' . $origin);
    header('Vary: Origin');
}

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
    header('Access-Control-Allow-Headers: Content-Type, Authorization');
    header('Access-Control-Max-Age: 600');
    http_response_code(204);
    exit;
}

Частые ошибки и как их избежать

  • BOM и пробелы: сохраняйте файлы в UTF‑8 без BOM, не закрывайте PHP-теги в файлах с чистым PHP-кодом.
  • Вывод до заголовков: никакого echo/var_dump до header(). Используйте лог в файл вместо вывода на экран.
  • Нет exit после редиректа: всегда завершайте скрипт после Location.
  • Неверный статус при POST‑редиректе: используйте 303 для PRG, 307/308 — когда важно сохранить метод.
  • Кеш не инвалидируется: обновляйте ETag/Last-Modified и корректно отвечайте 304.

Отладка заголовков

<?php
print_r(headers_list()); // Какие заголовки уже выставлены

if (headers_sent($f, $l)) {
    error_log("Headers sent at $f:$l");
}

Мини‑шпаргалка

  • JSON: header('Content-Type: application/json; charset=UTF-8')
  • Редирект: header('Location: /url', true, 302); exit;
  • PRG: 303 See Other
  • Кеш: Cache-Control: public, max-age=...
  • Валидация кеша: ETag, Last-Modified + 304
  • Файлы: Content-Disposition: attachment
  • Безопасность: X-Content-Type-Options: nosniff, X-Frame-Options

Что дальше изучать

Если хотите системно прокачать PHP с нуля до уверенной разработки бэкенда и БД, посмотрите программу и примеры из курса: Прокачать PHP на живых проектах: «PHP и MySQL с Нуля до Гуру 3.0».

Теперь вы знаете, как уверенно управлять HTTP‑заголовками в PHP и избегать «Headers already sent». Сохраните шпаргалку и переиспользуйте сниппеты в своих проектах!

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.