Недавно я купил новый MacBook Pro. До того, как я получил свой MacBook Pro, я работал над веб-сайтом на своем настольном компьютере. И теперь я хочу перенести этот код на свой новый MacBook Pro.
Проблема в том, что когда я передал код (я положил его на Dropbox и просто загрузил его на свой MacBook Pro), я начал видеть множество сообщений об ошибках в своем PHP-коде.
Сообщение об ошибке, которое я получаю:
Предупреждение. Невозможно изменить информацию заголовка – уже отправленные заголовки (вывод запущен в /some/file.php:1) в /some/file.php в строке 23
Я провел некоторое исследование по этому вопросу, и кажется, что эта ошибка чаще всего возникает из-за новой строки, простого пробела или любого вывода перед знаком <?php
. Я просмотрел все места, где у меня есть файлы cookie, которые отправляются в HTTP-запросе, а также где я использую функцию header()
. Я не обнаружил никаких выходных данных или пробелов, которые могли бы помешать и вызвать эту проблему.
Примечательно, что ошибка всегда говорит о том, что вывод запускается в строке 1. Что заставило меня задуматься, есть ли какие-то различия в кодировании в том, как операционные системы Mac OS X и Windows обрабатывают новые строки или пробелы? Или может ли передача Dropbox что-то испортить?
Код на одном из сайтов (login.php), который вызывает ошибку:
<?php include "mysql_database.php"; login(); $id = $_SESSION['Loggedin']; setcookie("login", $id, (time()+60*60*24*30)); header('Location: ' . $_SERVER['HTTP_REFERER']); ?>
функция входа:
function login() { $connection = connecttodatabase(); $pass = ""; $user = ""; $query = ""; if (isset($_POST['user']) && $_POST['user'] != null) { $user = $_POST['user']; if (isset($_POST['pass']) && $_POST['pass'] != null) { $pass = md5($_POST['pass']); $query = "SELECT ID FROM Anvandare WHERE Nickname='$user' AND Password ='$pass'"; } } if ($query != "") { $id = $connection->query($query); $id = mysqli_fetch_assoc($id); $id = $id['ID']; $_SESSION['Loggedin'] = $id; } closeconnection($connection); }
Полная ошибка:
Warning: Cannot modify header information - headers already sent by (output started at /Users/name/GitHub/website/login.php:1) in /Users/namn/GitHub/website/login.php on line 9
Проверьте, есть ли перед вашим тегом открытия php пробелы. Также попробуйте сохранить файл из блокнота ++ с использованием оконных окон (crlr). (Edit> EOL Conversion> Формат Windows)
Примечательно, что ошибка всегда говорит о том, что вывод запускается в строке 1. Что заставило меня задуматься, есть ли какие-то различия в кодировании в том, как операционные системы Mac OS X и Windows обрабатывают новые строки или пробелы? Или может ли передача Dropbox что-то испортить?
Не переделывайте код или не беспокоитесь о вызовах header()
или даже о файлах cookie. Это не проблема.
Проблема в том, что окончание строк Windows отличается от окончаний линии Mac. Подробнее здесь .
Различные операционные системы используют разные символы для обозначения конца строки:
- Unix / Linux / OS X использует LF (строка, '\ n', 0x0A)
- Маки до OS X используют CR (возврат каретки, '\ r', 0x0D)
- Windows / DOS использует CR + LF (возврат каретки, за которым следует линия, '\ r \ n', 0x0D0A)
И то, что происходит в таких случаях, как форматирование страницы, заставляет парсер PHP в Apache задушить файлы. Возможно отправка контента в браузер до того, как вы намереваетесь при вызове header()
или настройке файлов cookie. С технической точки зрения окончание завершенных строк заставляет «заголовок» отправляться, потому что сам файл выводит данные в браузер непреднамеренно.
Решение может заключаться в том, чтобы избежать использования Dropbox и просто скопировать файлы на флэш-накопитель и перенести его таким образом. Это идея, но я не уверен, что Dropbox был виновником этого. Это означает, что проблема может сохраниться даже при копировании файлов на флешку.
Или если это не сработает, сделайте так, как говорится в статье, и скачайте хороший инструмент для редактирования текста, например TextWrangler . Просто загрузите файлы в TextWrangler и затем вручную измените окончание строки, чтобы они были Mac (CR)
и сохранили файлы.
Другим долгосрочным решением этой проблемы может быть использование системы управления версиями, такой как git
сочетании с учетной записью GitHub для управления вашим кодом. Преимущество заключается в том, что нажатие кода на GitHub и извлечение кода из GitHub, сам процесс будет иметь дело с кросс-платформенными линиями, заканчивающими головные боли. И вам не нужно беспокоиться о непреднамеренных странностях, вызванных прямой копией файлов для службы, такой как DropBox.
Но опять же, довольно убедительно, это не имеет никакого отношения к Dropbox. Все о концах строк Windows отличается от окончаний строк в Mac OS X.
EDIT: Есть несколько интересных идей о том, как обрабатывать массовое преобразование окончаний строк Windows в конец строки Mac OS X в Mac OS X Hints . Наиболее интересным является использование zip
и unzip
для облегчения процесса. Я не пробовал это, так остерегаюсь! Но это похоже на то, что стоит тестировать, поскольку последние строки указывают, BTW, это флаг «-a» для распаковки, что приводит к тому, что файлы ascii преобразуют свои строки. :
Я всегда использовал следующее (в файле с именем
fixascii
):#!/bin/sh zip -qr foo.zip "$@" && unzip -aqo foo.zip && rm foo.zip
И затем выполните его как:
fixascii [files or directories to convert]
Что имеет преимущество по сравнению с большинством других команд, поскольку вы можете указать его безнаказанно на все дерево каталогов и обработать все файлы в нем и не повредить любые двоичные файлы, которые могут иметь строку бит в них, которые выглядят как конец строки.
Я видел слишком много раз, когда кто-то искажал тонну изображений и других двоичных файлов, пытаясь исправить линейные окончания в текстовых файлах с помощью dos2unix или tr в сочетании с find, но не смог убедиться, что обрабатывались только текстовые файлы. Разархивируйте, какие файлы являются ascii, преобразуют их и оставляют только двоичные файлы.
BTW, это флаг «-a» для распаковки, что приводит к тому, что файлы ascii преобразуются в окончание строк.
А затем посмотрите официальную страницу man для unzip
в опции -a
(конвертировать текстовые файлы); акцент мой:
Обычно все файлы извлекаются точно так, как они хранятся (как «двоичные» файлы). Параметр -a вызывает файлы, идентифицированные zip, в виде текстовых файлов (те, у которых метка «t» в списках zipinfo, а не «b»), автоматически извлекаются как таковые, конвертирование окончаний строк, символов конца файла и символа при необходимости. (Например, файлы Unix используют линейные каналы (LF) для конца строки (EOL) и не имеют маркера конца файла (EOF), Macintoshes использует возврат каретки (CR) для EOL, а большинство операционных систем для ПК используют CR + LF для EOL и control-Z для EOF. Кроме того, в мэйнфреймах IBM и в Мичиганской терминальной системе используется EBCDIC, а не в более общем наборе символов ASCII, а NT поддерживает Unicode.) Обратите внимание, что zip-идентификация текстовых файлов отнюдь не является идеально; некоторые «текстовые» файлы могут быть двоичными и наоборот. unzip поэтому печатает '' [текст] '' или '' [binary] '' как визуальную проверку для каждого файла, который извлекает при использовании опции -a. Параметр -aa заставляет все файлы извлекаться как текст независимо от предполагаемого типа файла.
EDIT: Кроме того, если у вас есть доступ к машине Linux, вам может dos2unix
проверка dos2unix
. Подробнее здесь . И нашел еще один вопрос о переполнении стека.
Наконец нашел простой способ исправить это! Я просматривал файл php.ini, когда сталкивался с опцией, которая называется: auto_detect_line_endings, и имеет значение по умолчанию: Off.
Описание этой опции:
; If your scripts have to deal with files from Macintosh systems, ; or you are running on a Mac and need to deal with files from ; unix or win32 systems, setting this flag will cause PHP to ; automatically detect the EOL character in those files so that ; fgets() and file() will work regardless of the source of the file. ; http://php.net/auto-detect-line-endings
Это именно то, что я искал!
Я просто использовал функцию ini_set () в начале моего файла базы данных (который я загружаю на каждую php-страницу) и, похоже, решил проблему для меня! Функция ini_set () также возвращает параметр, измененный в файле php.ini, в нормальный режим, когда скрипт завершен.
Полная строка функции ini_set (), которую я использовал:
ini_set("auto_detect_line_endings", true);
Спасибо всем за помощь!
Дополнительная информация о функции ini_set () здесь: функция ini_set ()
Дополнительная информация об опции auto_detect_line_endings здесь: Опция автоматического определения конца строки