I have a docx file and I need to replace some text. This is done inside codeigniter framework; here is the code:
$this->load->library('word');
$template = $this->word->loadTemplate($_SERVER['DOCUMENT_ROOT'].'/doc/assets/doc3.docx');
$template->setValue('replacename', 'new');
$template->save($_SERVER['DOCUMENT_ROOT'].'/doc/assets/helloWorld.docx');
When I open the new file I still get "replacename" instad of "new". "replacename" is formatted with Verdana font, 9pt font size (no underline or bold). Why it doesn't work? Removing ${ } from setValue function (and from doc file) it works
It turns out that when you add text to a word file, it sometimes creates extra tags in the underlying xml file. So (pseudo code) ${NAME}
can become <tag1>${</tag1><tag2>NAME</tag2><tag3>}</tag3>
Because of this, phpword can't find your needle.
I'm using a mac with microsoft word and i can just cut all the contents of the word file and paste them again.
Word will than recreate the underlying xml file in which ${NAME} is 1 tag instead of 3.
here i try and working well,
setValue function does not work because it include the format of word after generate to web. so the text you might replace not found.
the solution is just type your ${replaceKey} to notepad and copy it to your_template.docx it working for me.
notepad make all word format not included to the template so the function setValue can found it as expected.
Hope it Helping you guys.
I found the solution in http://phpword.codeplex.com/workitem/57... the problem seems to be when word generates his own code.
for the solution, just rename extension your template to zip, check in a file named 'document.xml' into 'word' folder, and search your code value... it should be like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14">
<w:body>
<w:p w:rsidR="00AC49DC" w:rsidRDefault="00243DD6">
<w:r>
<w:t>${test1}</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00243DD6" w:rsidRDefault="00243DD6">
<w:r>
<w:t>${test2}</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00243DD6" w:rsidRDefault="00243DD6">
<w:r>
<w:t>${test3}</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00243DD6" w:rsidRDefault="00243DD6">
<w:r>
<w:t>${test4}</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00243DD6" w:rsidRDefault="00243DD6">
<w:r>
<w:t>${</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
<w:r>
<w:t>test5}</w:t>
</w:r>
</w:p>
<w:sectPr w:rsidR="00243DD6" w:rsidSect="00C107D0">
<w:pgSz w:w="12240" w:h="15840" w:code="1"/>
<w:pgMar w:top="907" w:right="907" w:bottom="907" w:left="907" w:header="720" w:footer="720" w:gutter="0"/>
<w:cols w:space="720"/>
<w:docGrid w:linePitch="272"/>
</w:sectPr>
</w:body>
</w:document>
Just add 2 function to the file "TemplateProcessor.php"
public function setValueAdvanced($search_replace)
{
foreach ($this->tempDocumentHeaders as $index => $headerXML) {
$this->tempDocumentHeaders[$index] = $this->setValueForPartAdvanced($this->tempDocumentHeaders[$index], $search_replace);
}
$this->tempDocumentMainPart = $this->setValueForPartAdvanced($this->tempDocumentMainPart, $search_replace);
foreach ($this->tempDocumentFooters as $index => $headerXML) {
$this->tempDocumentFooters[$index] = $this->setValueForPartAdvanced($this->tempDocumentFooters[$index], $search_replace);
}
}
protected function setValueForPartAdvanced($documentPartXML, $search_replace)
{
$pattern = '/<w:t>(.*?)<\/w:t>/';
$rplStringBeginOffcetsStack = array();
$rplStringEndOffcetsStack = array();
$rplCleanedStrings = array();
$stringsToClean = array();
preg_match_all($pattern, $documentPartXML, $words, PREG_OFFSET_CAPTURE);
$bux_founded = false;
$searching_started = false;
foreach($words[1] as $key_of_words => $word)
{
$exploded_chars = str_split($word[0]);
foreach($exploded_chars as $key_of_chars => $char)
{
if ($bux_founded)
{
if ($searching_started)
{
if ($char == "}")
{
$bux_founded = false;
$searching_started = false;
array_push($rplStringEndOffcetsStack, ($word[1]+mb_strlen($word[0])+6));
}
}
else
{
if ($char == "{")
{
$searching_started = true;
}
else
{
$bux_founded = false;
array_pop($rplStringBeginOffcetsStack);
}
}
}
else
{
if ($char == "$")
{
$bux_founded = true;
array_push($rplStringBeginOffcetsStack, $word[1]-5);
}
}
}
}
for($index=0; $index<count($rplStringEndOffcetsStack); $index++)
{
$string_to_clean = substr($documentPartXML, $rplStringBeginOffcetsStack[$index], ($rplStringEndOffcetsStack[$index]-$rplStringBeginOffcetsStack[$index]));
array_push($stringsToClean, $string_to_clean);
preg_match_all($pattern, $string_to_clean, $words_to_concat);
$cleaned_string = implode("", $words_to_concat[1]);
$cleaned_string = preg_replace('/[${}]+/', '', $cleaned_string);
array_push($rplCleanedStrings, $cleaned_string);
}
for ($index=0; $index<count($rplCleanedStrings); $index++)
{
foreach($search_replace as $key_search => $replace)
{
if ($rplCleanedStrings[$index] == $key_search)
{
$documentPartXML = str_replace($stringsToClean[$index], "<w:t>".$replace."</w:t>", $documentPartXML);
break;
}
}
}
return $documentPartXML;
}
How to use: Use an array as the only parameter of function "setValueAdvanced", where "key" - a word, that we want to replace, and "value" - phrase we want to paste instead. Important: Inside a MS Word file use "${word_to_replace}" to "mark" a word that we want to replace, but key of an array should be "word_to_replace", without "${}"
Example code:
require_once 'PhpWord/Autoloader.php';
use PhpOffice\PhpWord\Autoloader;
use PhpOffice\PhpWord\Settings;
define('CLI', (PHP_SAPI == 'cli') ? true : false);
define('EOL', CLI ? PHP_EOL : '<br />');
define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php'));
define('IS_INDEX', SCRIPT_FILENAME == 'index');
Autoloader::register();
Settings::loadConfig();
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('your_file_name.docx');
$search_replace_array = array(
'msword_hello'=>'Hello', #inside a MS Word file ${msword_hello} will change to Hello
'msword_world'=>'World' #${msword_world} will change to World
);
$templateProcessor->setValueAdvanced($search_replace_array);
$templateProcessor->saveAs('your_file_name_changed.docx');
You can use new Template class with new method setValue()
<w:p w:rsidR="00243DD6" w:rsidRDefault="00243DD6">
<w:r>
<w:t>{</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
<w:r>
<w:t>test5}</w:t>
</w:r>
</w:p>
New method can replace it setValue('test5', 'MyValue');
Download new class: https://github.com/Arisse/PHPWord_CloneRow
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With