Php как создать файл с кодировкой

Обновлено: 02.07.2024

CSV очень удобный формат с точки зрения генерации, поскольку он очень просто устроен. В этой заметке разберемся как устроены файлы с расширением .csv , как их создавать и разбирать (парсить) в PHP. Делается это очень просто.

Ищем WP-разработчика! Фулл-тайм, удаленка, хорошая зарплата, соц. пакет. Подробности.
Компания Boosta.

Ниже приведены простые PHP функции для создания и парсинга csv файлов. Никаких библиотек - для CSV это лишнее!

Формат CSV

Чтобы понимать суть вещей, нужно разобраться в спецификации CSV файлов, как устроен формат. Давайте коротко.

CSV (Comma-Separated Values — значения, разделённые запятыми) — текстовый формат, предназначенный для представления табличных данных.

Каждая строка файла — это одна строка таблицы.

Разделителем значений колонок является символ: , (запятая). Для русского языка используется ; (точка с запятой), потому что в русском запятая используется в дробных числах.

Значения, содержащие зарезервированные символы: " , ; \r\n или \n или \r (двойная кавычка, запятая, точка с запятой, новая строка) обрамляются двойными кавычками " .

Если в значении встречаются двойные кавычки " , то они должны выглядеть как двое кавычек подряд "" .

Это все что нужно знать, чтобы работать с CSV!

Пример для рус. языка:


Пример для англ. языка:


Wiki-справка

Большинство программ под CSV понимают более общий формат DSV (delimiter-separated values — значения разделённые разделителем), допускающий использование иных символов в качестве разделителя. В частности, в русской и других локалях запятая по умолчанию зарезервирована под десятичный разделитель. Поэтому как разделитель используется точка с запятой или табуляция (формат TSV).

Сегодня под CSV понимают набор значений, разделенных какими угодно разделителями, в какой угодно кодировке с какими угодно окончаниями строк. Это значительно затрудняет перенос данных из одних программ в другие, несмотря на всю простоту формата.

Создание CSV файла в PHP

Для создания CSV файла, достаточно создать текстовый файл, используя в нужных местах необходимые разделители столбцов и строк.

Важным моментом, является кодировка файла. Для корректного отображения кириллицы следует использовать кодировку cp1251 (windows-1251).

Разделитель колонок

Для русского языка символом-разделителем является ; (точка с запятой). Для англ. , (запятая).

Строки содержащие спец символы: " , ; \r\n или \n или \r должны быть в двойных кавычках "строка" .

Двойные кавычки внутри строки, нужно «очистить» поставив перед кавычкой еще одну такую же кавычку: строка "csv" превратиться в "строка ""csv""" . Обрамление в кавычки нужно, чтобы можно было внутри значений колонок использовать разделители ; , , и не переживать что что-то сломается при чтении файла.

Разделитель строк

Для разделения строк в csv файлах можно использовать \r\n (возврат каретки и перенос строки, CR LF). В этом случае, если нужен перенос строки внутри значения колонки, то там используется просто \n .

Также, для разделения строки, может использоваться просто \n (перенос строки, LF). В этом случае, перенос строки внутри значения колонки должен обозначаться как \r (возврат каретки CR).

Функция для создания CSV файла


меню

Чтение CSV файла в PHP

Когда нужно получить данные из CSV файла, т.е. разобрать его и получить данные в переменную, можно использовать встороенную в PHP функцию str_getcsv() .

Есть еще функция fgetcsv() , но она оказалась капризной и не всегда работает как нужно (может перепутать переносы строк).

Вариант на базе функции str_getcsv() :

Конвертация .lsx , .xlsx файла в .csv

Чтобы перевести Excel файл в CSV, нужно открыть его в Excel и сохранить в формате .csv :


Если такую конвертацию нужно сделать программно, смотрите в сторону онлайн конвертеров с API или готовых библиотек.

Сталкивались с такой задачей и знаете более универсальный способ? Прошу поделиться в комментариях.

Я столкнулся и потратил несколько часов перебирая всякий не универсальный «мусор» из гугла - то одно не работает, то другое, то библиотеку нужно ставить «хитро-мудрую». Так и появилась эта заметка.

Тема, конечно, интересная. Только этот код в реальных условиях работать не будет.

Что с ним не так?

1) Разделитель поля может быть любой. Например, '\', '|' или ещё что похуже.
2) Символ ограничителя поля может быть как двойная, так и одинарная ковычка.
3) Неплохо бы использовать unset в коде. Память на сервере всё-таки не резиновая. Одно дело загрузка файла с пару сотен строк кода, а другое если их пару десятков миллионов.

1) Ты параметр $col_delimiter не увидел похоже, суй туда какой угодно разделитель!

2) Для текущего кода (обоих) это учитывается: в первом создается строка с двойной кавычкой и только. Во втором строка парсится PHP функцией str_getcsv() которая обе кавычки понимает.

3) В каком месте там unset по твоему поможет хорошо избавится от потерь памяти? Если у тебя файл выходит за пределы памяти, что редкость с текущими параметрами серверов, то это пожалуй экстра случай и подход уже нужен будет принципиально другой. Файл читать или записывать нужно будет частями или построчно, а не так целиком. По аналогии ты в ВП запихай 50 000 рубрик и все приехали, нужно будет костыли вставлять для нормальной работы. Но ВП почему-то самая популярная CMS, как же так? Я не писал код на все случаи жизни, код покрывает 80% случаев, остальное уже требует отдельного подхода, а этот код можно взять за основу.

Этот код в реальных условиях у меня работает! Может там и есть баги, но я их не встречал.

П.С. просмотрел второй код, добавил unset() маловероятно что много толку от этого, но лишним не будет.

Не "суй туда какой угодно разделитель", а все возможные разделители для csv файлов. Ты бы ещё менеджеру предложил указывать разделитель для файла, который он загружает

"с текущими параметрами серверов". Поверь, кривым кодом можно положить сервер даже с очень хорошими характеристиками. Я обычно беру за правило, если переменная больше не будет использоваться она должна умереть (или обнулиться). Когда поработаешь с хайлоудом, то начинаешь понимать цену памяти)

И вообще, если пишешь рабочую программу, нужно это делать хорошо, а не в стиле "мой первый скрипт"!

Мои сайты сделаны в кодировке windows-1251, включая БД. Возникла необходимость получить файл в кодировке UTF-8 (собираю dump-файл базы). Как оказалось, преобразование из одной кодировки в другую - задача не тривиальная. В этой статье я попытаюсь разложить по полочкам, что к чему. Поле деятельности: Apache/2.2.15 (Win32) PHP/5.3.5. Во внимание беру только две кодировки, UTF-8 и Windows-1251 (aka cp1251), но многое из сказаного относится к преобразованиям в любых кодовых страницах.


Прежде чем хвататься за клаву и "превращать воду в вино"..

часть Рекомендательная

Приведу несколько примеров получающихся заголовков.
Настройки PHP: windows-1251 (php.ini: default_charset=windows-1251)

Настройки Apache: UTF-8 (.htaccess: addDefaultcharset UTF-8)

Настройки PHP и Apache: не указана кодировка

часть Функциональная (PHP)

Переключить кодировку PHP-препроцессора на время выполнения скрипта можно так:

С другой стороны, перед передачей ответа можно явно указать заголовок с кодировкой:

header ('Content-Type: text/html; charset=windows-1251');

Кодировка файла скрипта. PHP-файл - это обычный текстовик, все символы в нем кодируются набором байт с учетом установленной кодировки текста. Если в скрипте используются функции типа echo(), fwrite() и т.п., причем текст их параметров записан в этом же скрипте, то здесь так же важна кодировка самого файла скрипта! Пример файла some.php:

БД, внешние файлы. Если кодировка текста, полученного из таблицы/файла/сайта, отличается от нужной, то придется перекодировать. В этом месте наконец-то можно использовать функции типа iconv(), utf8_encode(), ob_iconv_handler(), mb_output_handler() и т.п., а так же пользовательские функции перекодирования.

Назначение всех этих функций разное. Например, utf8_encode() поддерживает только следующее преобразование: ISO-8859-1 (aka Latin-1) > UTF-8. Две других функции, ob_iconv_handler() и mb_ output_handler(), можно использовать только как callback-функции для буфферизированного вывода (этот момент до меня долго доходил). Пример использования: здесь источником текста является сам скрипт (кодировка файла: UTF-8), настройки web-сервера и PHP не суть важны, в браузере можно переключиться.

Результатом в браузере будут две строки, первая будет читаться при выборе кодировки страницы "UTF-8" (см. в настройках браузера), вторая - "Кириллица (Windows-1251)". Это был учебный пример, реальное применение перекодирования "на лету": нужно вернуть пользователю html-страницу в другой кодировке.

Создание файла с нужной кодировкой. Тут вроде особых проблем нет, используем iconv() или сразу пишем в нужной кодировке. Зато есть ньюанс с UTF-8 файлами. Следующий код создает файл с кодировкой UTF-8 (файл скрипта в той же кодировке):

Некоторые программы не корректно определяют кодировку полученного файла. Выход: дописывать сигнатуру UTF-8 в начале файла. Для этого нужно раскоментировать строку (3). Что такое "сигнатура UTF-8", цитата из Википедии: "Порядок байтов (BOM, сигнатура) Многие программы Windows (включая Блокнот) добавляют байты 0xEF, 0xBB, 0xBF в начале любого документа, сохраняемого как UTF-8. Это метка порядка байтов Юникода (англ. Byte Order Mark, BOM), также её часто называют сигнатурой (соответственно, UTF-8 и UTF-8 with Signature). По наличию сигнатуры программы могут автоматически определить, является ли файл закодированным в UTF-8, однако файлы с такой сигнатурой могут некорректно обрабатываться старыми программами, в частности xml-анализаторами. Такие редакторы, как Notepad++, Notepad2 и Kate позволяют явно указывать, следует ли добавлять сигнатуру при сохранении UTF-файлов."

Post Scriptum

Нашел на форумах пользовательскую функцию преобразования windows-1251 <-> UTF-8. Может пригодится когда-нибудь. У меня она работала криво в направлении Win -> UTF. Пофиксил, все работает:)

Баг был в строке (20): функция str_replace() гонит на половине алфавита. Заменяет русскую win-букву на двухбайтное UTF-значение, а потом а этой замене опять заменяет первый байт(!), который в win-1251 так же соответствует букве, на UTF-значение. Причем другая половина алфавита нормально заменяется.

fwrite функция PHP или file_put_content не заботится о метаданных файла, он просто записывает данные в хранилище и все. Это приводит к простой гипотезе, что кодировка текстового файла определяется его данными, поэтому вам необходимо преобразовать данные, которые вы будете записывать в файл, в определенный формат.

В PHP вы можете добиться этого, используя функцию iconv, пытаясь обнаружить кодировку ваших данных (обычно UTF-8) и преобразовать их в новый формат, а именно Windows-1252 (CP1252):

Выходной файл будет автоматически распознан вашим любимым текстовым редактором в кодировке Windows-1252:

Windows 1252 Текст PHP

И это все нормально. Если содержимое ваших файлов не имеет специальных символов, содержимое может быть распознано текстовым редактором как UTF-8, поэтому ваш единственный вариант будет использовать инструмент CLI для преобразования кодировки файла (читай следующий абзац).

Если файл все еще без правильной кодировки

Если после использования простого PHP для написания содержимого вручную в вашем файле не используется нужная кодировка в содержимом файла, вам может понадобиться использовать вместо системного уровня способ установки кодировки файла.

Предпочтительный и самый простой способ сделать это с помощью CLI - это iconv. Этот инструмент CLI преобразует кодировку символов во входном файле из одного набора кодированных символов в другой. Результат записывается в стандартный вывод, если иное не указано параметром --output или просто перенаправлением вывода с помощью cli, например:

Вы можете использовать Exec функция PHP запустить программу iconv с указанными аргументами, доступную в любой ОС на базе UNIX или в Windows (используя Cygwin).

Как уже упоминалось, большинство текстовых редакторов, которые используют автоматический детектор кодирования, решают, какую кодировку использовать в соответствии с содержимым, поэтому обычно, хотя строки, хранящиеся в файле с PHP, которые имеют кодировку Windows-1252 (CP1252), UTF-8 режим будет использоваться. Это означает, что обнаружение кодировки на основе содержимого основано только на эвристике, поэтому не гарантирует правильности кодировки, используемой для открытия файла.

Однако содержимое не обманывает, поэтому, если вы попытаетесь открыть содержимое файла в кодировке Windows-1252 в кодировке UTF-8, вы увидите странные символы в текстовом редакторе:

Windows1252 (CP1252) текст, открытый с помощью UTF-8

Однако если текстовый редактор считывает содержимое файла с кодировкой Windows-1252 (CP1252), он будет прочитан правильно:

На сколько бы это глупо не казалось, но для удачного выставления кодировки необходимо выполнить целых 11(!) правил.
Хочу зарание предупредить, если какая-то из настроек в .htaccess повлечет за собой ошибку 500, это значит, что хостинг запретил менять этот параметр на сервере. В таком случае проверьте тот факт, что у Вас UTF-8 и в случае чего обратитесь к админам хостинга.
И для тех, кто попал на эту страницу с вопросами об Ajax: Ajax работает в кодировке UTF-8.

Правило №1: Указываем в HTML верстке в теге первой строчкой, кроме случаев, где мы будем использовать тег , так как он так же как и кодировка имеет приоритет над расположением, следующий код:


Правило №2: Указываем кодировку для PHP и самого файла, для этого нам необходимо выставить заголовок функцией header(). Выставляем его в самом начале нашего файла (абсолютно в самом начале), сразу после указания уровня вывода ошибок:

Правило №3: Кодировка для подключения к к БД MySQL. Устанавливается после подключения к БД и выбора бд (mysql_connect, mysql_select_db). Если у нас модуль mysql:

или улучшенный модуль mysqli:


Правило №4: Кодировка в .htaccess:


Правило №5: Кодировка для библиотеки mb, начиная с версии php 5.4 можно не указывать, так как по умолчанию будет использоваться именно UTF-8. Ну а пока прописываем её в файле .htaccess:

Либо в самом PHP, что в итоге выполнит одни и те же действия:


Правило №6: При сохранении файлов (обязательно ВСЕХ!) выбрать кодировку UTF-8 without BOM, повторюсь, without BOM - это необходимая настройка, в противном случае Ваш сайт не будет работать как надо. Для тех, кто пользуется удобной программой DreamWeaver:
Modify => Page Properties => Title/Encoding и выставляем "Encoding: UTF-8", после чего нажимаем ReLoad, убираем галочку с BOM "Include Unicode Signature (BOM)". Apply + OK.
Модификации => Свойства страницы => Заголовок/Кодировка и выставляем кодировку UTF-8. Нажимаем "перезагрузить", убрали галочку с Подключить Юникод Сигнатуры (BOM). Применить и OK.

Правило №7: если на данный момент какой-то из текстов был введён на странице или в БД - его необходимо перенабрать. Дело в том, что символ в одной кодировке представляет один набор бит для русских символов, а в другой - другой. Именно поэтому необходимо его либо перенабрать, либо перекодировать. Современные программы имеют возможность перевести текст из одной кодировки в другую. Об этой возможности интересуйтесь в мануалах Ваших программ.

Правило №8: Есть исключение, когда текст приходит к Вам на страницу с другого сайта в другой кодировке. Тогда на PHP есть удобная функция для перевода из одной кодировки в другую:


Правило №9: Для строковых функций strlen, substr, необходимо использовать их аналоги на библиотеке mb_, а именно: mb_strlen, mb_substr, то есть к функции дописываем mb_ .

Правило №10: Для работы с регулярными выражениями необходимо указывать модификатор u . Это обязательный параметр!

Правило №11: Для CSS файлов указывается кодировка так:


В заключение скажу, что символы в кодировке WIN-1251 состоят из 1 байта, то есть 8 бит, а в свою очередь в кодировке UTF-8 символы могут состоять от 1 до 4 байт, всё дело в том, что кодировка UTF-8 позволяет создавать мультиязычные сайты, так как все существующие в мире символы в ней присутствуют.
Ради любопытства русская буква в кодировке UTF-8 занимает 2 байта, именно поэтому за 1 символ функция strlen возвращает длину 2, то есть 2 байта, а mb_strlen возвращает уже правильную длину в 1 символ.

Читайте также: