Pull to refresh

Не очень честная генерация DOC файлов на PHP

Reading time3 min
Views17K
У каждой задачи есть несколько вариантов решения. И иногда в угоду скорости приходится выбирать не самый красивый, зато работающий и выполняющий поставленные перед ним цели. Итак, в один не очень прекрасный день возникла необходимость реализовать следующую функцию: у каждой (почти) страницы сайта должны быть автоматически сгенерированные копии в форматах DOC и PDF. С сохранением всех таблиц и картинок внутри контента. И если с PDF всё относительно просто (tcpdf наш друг и брат), то с DOC'ом возникла морока. Под катом — пример решения данной задачи.В голову приходили последовательно такие варианты решения:
  • Установить на сервер OpenOffice (сервер на FreeBSD) и разобраться с преобразованием. Красивое решение, но время поджимало.
  • Сгенерировать вместо DOC'а файлик в формате RTF, благо формат открытый и библиотек для работы с ним много. Минус – готового преобразователя HTML->RTF (с, напомню, сохранением картинок и таблиц) я не нашел, а писать свою – для этого нужен определённый запас времени
  • Не очень честный — просто “в лоб” сохранить HTML страницу с расширением DOC – Word 2003 и выше откроет без проблем, проверено. Плюс – отличнейшая скорость преобразования и сохранение всей верстки. Минус – картинки таким образом не сохранить (да и честность метода несколько хромает).
Вот собственно из третьего варианта и родилось окончательное решение: создавать документ формата MHT, интегрировать в него картинки и сохранить с расширением DOC. Для генерации использовалась простенькая библиотека, взятая отсюда .Код не претендует на красоту и универсальность, более того, в нем есть проблемы, не актуальные для того сайта, но главное – он работает, и его достаточно, чтобы разобраться в теме.

Пример применения написанной функции:

$link="m.habrahabr.ru/post/136811/";
CreateDOC($link,"test.doc");



А вот и исходный код функции:

function CreateDOC($link,$filename)
{

//выделяем базовый домен, пригодится
$base_link=$link;
$base_link=explode("/",$link);
unset($base_link[count($base_link)-1]);
$base_link[]="";
$base_link=implode("/",$base_link);

//получаем текст страницы
$get_text=file_get_contents($link);

//создаём объект, который и будет генерировать нам конечный mht
$MhtFileMaker = new MhtFileMaker();


//подключаем картинки к файлу

//более прямая регулярка, вытаскиваюшая пути картинок, спасибо хабраюзеру FlexIDK
preg_match_all('@<img(.*)?src="([^"]+)"@ui', $get_text, $matches);

foreach ($matches[4] as $img)
	{
		$img_tmp=$img;
		$img_tmp_old=$img;
		
		//помните, базовая ссылка? пригодилась же!
		if (strpos($img_tmp,"http")===FALSE) 
			$img_tmp=$base_link.$img_tmp;
	
	
		//выделяем путь картинки БЕЗ адреса домена
		$img_array=explode("//",$img_tmp);
		$img_name_only=$img_array[1];
		$img_name_only=explode("/",$img_name_only);
		unset($img_name_only[0]);
		$img_name_only=implode("/",$img_name_only);

		//заменяем адрес картинки на относительный (без домена)
		$get_text=str_replace($img_tmp_old,$img_name_only,$get_text);
	
		//добавляем картинку в конечный файлГ
		$MhtFileMaker->AddFile($img_tmp, $img_name_only, NULL);
};

//разобрали картинки, теперь создаём окончательный файл
$MhtFileMaker->AddContents("index.html","text/html",$get_text);

//сохраняем файл
$MhtFileMaker->MakeFile($filename);
};
Естественно, можно написать на основе этого гораздо более универсальный и прямой класс, но для наших целей этого было достаточно. Главное — данное решение работает, и достаточно быстро. Надеюсь, оно покажется кому то достаточно полезным.

Update: в комментариях протестировали получившийся файл — нормально он открывается только в Microsoft Word 2003 и выше, в сторонних продуктах (OpenOffice и другие) возникают проблемы. Так же в комментариях приведены ссылки на многие другие, более правильные методы преобразования

Update 2: Обновил исходник — FlexIDK предложил более удачную регулярку, выбирающую пути картинок без лишних символов.
Tags:
Hubs:
+21
Comments43

Articles