правка/создание doc файла

bars80081

Новичок
есть ли способ править доковский файл, как шаблон?
по принципу:

PHP:
$text = file_read($dir . '/web.doc');
$newtext = str_replace('{TTB_NAME}', 'QWERTQWERT', $text);
file_write($dir . '/newweb.doc');
или придётся писать его целиком заново?

пользователь указывает реквизиты, которые сохраняются в mysql БД, а затем скачивает документы с расширением doc, в которых эти реквизиты уже проставлены. в длинном договоре надо всего лишь заменить десяток переменных


мне уже советовали http://php.net/manual/ru/book.com.php , но на линуксовом сервере оно не пойдёт
также использовать rtf нельзя из-за потери разных разностей в тексте


в принципе, моя мысль всё пытается решить задачу в лоб: к примеру, на месте вставляемого значения находится строка с фиксированной длинной ПЕРЕМЕННАЯ_ДЛЯ_ЗАМЕНЫ_ЮРИДИЧЕСКИЙ_АДРЕС___________ещё-сколько-то-символов-для-дозаполнения-по-принципу-CHAR, которую мы просто заменяем простым str_replace
но пока что-то не удаётся осилить перевод. латинские символы вроде удаётся так менять, дополняя каждый символ кодом \x00. кириллица же завершается \x04 , однако, сопоставить коды самих символов не получается. к примеру, символ "Ю" имеет код DE (222), но в winhex-редакторе открыв doc-овский файл он обозначен двумя байтами 2E 04, в то время как "U" имеет код 55 (85), а в редакторе 55 00
как их сопоставить?
 

bars80081

Новичок
точно, спасибо, именно так


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

PHP:
$needle = array('DEFINE_JURE_ADRES', 'DEFINE_JURE_RS');
$str = array('ООО "Самсунг"', '7894623');
$newtext = str_replace_in_doc($needle, $str, $text);


function str_replace_in_doc($needle = '', $str = '', $text = '') {
	$a_len = $a = $b = array();
	if(is_array($needle)) {
		$a_c = count($needle);
		for($i = 0; $i < $a_c; $i++) { $a_len[$i] = strlen($needle[$i]); }
		$a = $needle;
	} else {
		$a_c = 1; $a_len[0] = strlen($needle); $a[0] = $needle;
	}
	if(is_array($str)) {
		$b = $str;
	} else {
		$b[0] = $str;
	}
	
	$a = str_replace_in_doc_needle($a, $a_len, $a_c);
	for($i = 0; $i < $a_c; $i++) {
		if(empty($b[$i])) { $b[$i] = ''; }
		$b[$i] = str_replace_in_doc_str($b[$i], $a_len[$i]);
		$text = str_replace($a[$i], $b[$i], $text);
	}
	return $text;
}
function str_replace_in_doc_str($s, $a_len) {
	$s = iconv('UTF-8', 'UCS-2', $s);
	$b_len = strlen($s); $max = $a_len * 2;
	$len = min($b_len, $max);
	$n = ''; $arr = array();
	for($i = 0; $i < $len; $i++) {
		$add = (!($i%2)) ? 1 : -1;
		$arr[($i + $add)] = substr($s, $i, 1);
	}
	for($i = 0; $i < $len; $i++) { $n .= $arr[$i]; }
	for(; $i < $max; $i += 2) { $n .= "\x20\x00"; }
	return $n;
}
function str_replace_in_doc_needle($a, $a_len, $j_len) {
	$n = array();
	for($j = 0; $j < $j_len; $j++) {
		$n[$j] = '';
		for($i = 0; $i < $a_len[$j]; $i++) { $n[$j] .= substr($a[$j], $i, 1) . "\x00"; }
	}
	return $n;
}
вроде работает. заменяет в фразы DEFINE_JURE_ADRES и DEFINE_JURE_RS в тексте на подставку. если в новая фраза длиннее прежней, то новая обрезается под размер прежней. если наоборот, то новая фраза дополняется пробелами

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

bars80081

Новичок
как я понял, этот скрипт работает только с docx? но у подавляющего числа клиентов стоит winWord 97-XP, речь идёт о работе с форматом именно .doc
 

radioheaded

PHP нуб
doc — бинарный формат с заголовками а-ля FAT. То есть, там все секции размечены, их размеры записаны. Если вы хотите еще и размер изменить, то придется заголовки править. Сейчас уже есть даже официальная документация по формату — http://msdn.microsoft.com/en-us/library/cc313153.aspx . В мое время приходилось по крупицам собирать инфу.
 

fixxxer

К.О.
Партнер клуба
да проще выделить достаточно места, а остаток забивать пробелами нулевой ширины (были такие в юникоде)
 

bars80081

Новичок
да проще выделить достаточно места, а остаток забивать пробелами нулевой ширины (были такие в юникоде)
кстати, да. вообще, почти так и сделал, просто не допёр, что это уже и есть решение.
заменяю я ведь значениями из БД, а там они всё равно хранятся в полях ограниченной длины. осталось только все искомые размечать на ширину полей (там преимущественно varchar(255)), а дополнять пустоты не пробелами "\x20\x00", а пустыми символами "\x16\x00", в итоге в документе строки выглядят короткими.

тогда задача решена

спасибо всем
 
Сверху