Blog. Just Blog

Создание файла XLSX на PHP без сторонних библиотек

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Создание файла XLSX на PHP без сторонних библиотек
Создание файла XLSX на PHP без сторонних библиотек

В предыдущей статье я рассказал, как можно легко извлекать данные из файлов в формате XLSX. Раз можно извлекать, значит можно и генерировать такие файлы, тем более, что их формат уже разобран. Если требуется создавать файлы только со статичными данными, без формул, сводных таблиц, графиков и прочей красоты, то совсем не обязательно таскать тяжеленные библиотеки, можно воспользоваться приведенным в статье кодом.

Из PHPExcel я позаимствовал функцию, которая на входе получает линейный номер столбца, а на выходе возвращает буквенный номер столбца в экселевском представлении. Она нам понадобится для генерации XML-файла.
  1. function num2cell($col=0) {
  2.     static $cell_cache = array();
  3.  
  4.     if (!isset($cell_cache[$col])) {
  5.         if ($col<26) {
  6.             $cell=chr(65+$col);
  7.         }
  8.         elseif ($col<702) {
  9.             $cell=chr(64+($col/26)).
  10.                   chr(65+$col 26);
  11.         }
  12.         else {
  13.             $cell=chr(64+(($col-26)/676)).
  14.                   chr(65+((($col-26)%676)/26)).
  15.                   chr(65+$col%26);
  16.         }
  17.         $cell_cache[$col]=$cell;
  18.     }
  19.     else {
  20.         $cell=$cell_cache[$col];
  21.     }
  22.     return $cell;
  23. }
Для примера сгенерим двумерный массив данных 40000х100 ячеек. Часть ячеек будет содержать строковые данные, а часть - числовые. При этом некоторые строки в ячейках будут повторяться.
  1. $data=array();
  2.  
  3. for($y=0$y<40000$y++) {
  4.     for($x=0$x<100$x++) {
  5.         if (rand(0,100)<50) {
  6.             $data[$y][$x]=rand(0,1000000);
  7.         }
  8.         else {
  9.             $data[$y][$x]='Cell '.rand(0,100);
  10.         }
  11.     }
  12. }
Дальше нам понадобится файл-пустышка, на основе которого будет создаваться книга. Конечно, никто не мешает вам создать все необходимые файлы внутри книги самостоятельно, но с готовым шаблоном гораздо удобнее. Его можно хранить на диске и задействовать по мере надобности, а можно конвертнуть в base64 и хранить сразу в коде, не захламляя хост.

Шаблон XLSX-файлаШаблон XLSX-файла

XLSX.Template.zip (6,428 bytes)

Создание книги выполняется в несколько этапов. Как вы помните по предыдущей статье, строковые значения ячеек хранятся в отдельном файле sharedStrings.xml, а числовые значения и ссылки на строки записываются в файлы листов типа sheet1.xml. Поэтому первым действием будет извлечение уникальных строк из массива данных. Тут строки используются в качестве ключей массива, но беспокоиться об этом не надо, в PHP ключи массива спокойно могут достигать 128 мегабайт.
  1. // Предобработка: извлечение строк из массива данных
  2. $words=array();
  3.  
  4. foreach ($data as $row=>$cols) {
  5.     foreach($cols as $col=>$value) {
  6.         if (is_string($value)) {
  7.             if (!isset($words[$value])) {
  8.                 $words[$value]=count($words);
  9.             }
  10.         }
  11.     }
  12. }
Следующими двумя шагами создаем файлы sheet1.xml и sharedStrings.xml, последовательность этих действий значения не имеет. Оба файла имеют формат XML и требуют соблюдения определенной структуры. Чтобы скрипт не жрал память, запись выполняется сразу после создания каждой строки. По скорости это может быть медленнее, чем если сгенерировать в памяти XML-файл целиком и потом записать его на диск, но зато менее ресурсоемко. Выберите подходящее для вас решение, исходя из задачи.
  1. // Запись первого листа книги
  2. $f=fopen('sheet1.xml','w+');
  3.  
  4. $xml='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  5. <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  6. xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. mc:Ignorable="x14ac"
  9. xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
  10. <sheetViews>
  11. <sheetView tabSelected="1" workbookViewId="0" />
  12. </sheetViews>
  13. <sheetData>';
  14.  
  15. fwrite($f,$xml);
  16.  
  17. for($y=0$y<count($data); $y++) {
  18.     $xml='<row r="'.($y+1).'" spans="1:1">';
  19.     fwrite($f,$xml);
  20.  
  21.     for($x=0$x<count($data[$y]); $x++) {
  22.         $val=$data[$y][$x];
  23.         $r=num2cell($x).($y+1);
  24.         if (isset($words[$val])) {
  25.             $xml='<c r="'.$r.'" t="s"><v>'.$words[$val].'</v></c>';
  26.         }
  27.         else {
  28.             $xml='<c r="'.$r.'"><v>'.$val.'</v></c>';
  29.         }
  30.         fwrite($f,$xml);
  31.     }
  32.     $xml='</row>';
  33.     fwrite($f,$xml);
  34. }
  35.  
  36. $xml='</sheetData>
  37. </worksheet>';
  38. fwrite($f,$xml);
  39. fclose($f);
В тегах файла sharedStrings.xml надо обязательно указывать количество уникальных строк и их общее количество. В отличие от стационарного Excel, этот код учитывает уникальность, так что оба значения совпадают.

Еще было бы неплохо поэкспериментировать со строками на предмет наличия в них всяких HTML-тегов, служебных символов, пустых строк и всякого такого. У меня формат исходных данных известен, так что такие проверки и преобразования выполнять не придется.
  1. // Запись строковых данных
  2. $f=fopen('sharedStrings.xml','w+');
  3.  
  4. $xml='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  5. <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
  6. count="'.count($words).'"
  7. uniqueCount="'.count($words).'">';
  8. fwrite($f,$xml);
  9.  
  10. if (count($words)) {
  11.     foreach($words as $k=>$v) {
  12.         $xml='<si><t>'.$k.'</t></si>';
  13.         fwrite($f,$xml);
  14.     }
  15. }
  16. $xml='</sst>';
  17. fwrite($f,$xml);
  18. fclose($f);
Когда оба файла сформированы, надо упаковать их в создаваемую книгу. Делается это с помощью уже известного вам PHP-класса ZipArchive. Очередность упаковки файлов значения не имеет.
  1. // Упаковка файлов в книгу
  2. $z=new ZipArchive();
  3. $z->open('file.xlsx',ZipArchive::CREATE);
  4.  
  5. $z->addFile('sheet1.xml''xl/worksheets/sheet1.xml');
  6. $z->addFile('sharedStrings.xml''xl/sharedStrings.xml');
  7.  
  8. $z->close();
В принципе, на этом можно и остановиться, все минимально необходимые, но при этом достаточные действия для генерации файла XLSX выполнены. Из интересного: в файле \docProps\core.xml содержатся данные о создателе файла и времени его создания. Если это важно, то вы тоже можете создавать его динамически и добавлять в книгу, при открытии в Excel эти данные будут отображаться в свойствах файла.

Поделиться ссылкой ВКонтакте
Просмотров: 154 | Комментариев: 0

Метки: PHP

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 3 (0.0032 сек.) / Память: 4.5 Mb
Наверх