<?php
/**
* Allows Word 97/2000 templates to be used in a similar way to HTML templates.
* ie Allows subsititution of fields such as {NAME} defined in a .doc or a .dot
*
* Read comments for further instructions.
*
* IMPORTANT NOTE
* You MUST call the destroy() method when you have finished. Else you will be left
* with a zombi Word process on the server every time the class is used
*
* Contact me with comments/suggestions
*
* Requires: Windows NT (Easily extended to use DCOM, but not tested).
* Works with late version PHP3 and better
*
* @author Peter Cruickshank - php at krabi dot demon dot co dot uk
* @copyright This version is free for use/modification so long as my details are retained
*
*-----------------------------------------------------------------------------------
* History
* May01 Peter Cruickshank Created
* Jan03 Peter Cruickshank Reformatted for phpDoc. No changes to code
*
*-----------------------------------------------------------------------------------
*/
// WORD CONSTANTS ----------------------------------------------------------------------
define("wdReplaceOne", 1);
define("wdReplaceAll", 2);
define("wdStory", 6);
define("wdSectionBreakNextPage",2);
define("wdOrientPortrait", 0);
define("wdOrientLandscape",1);
// THE CLASS ---------------------------------------------------------------------------
class wd97template {
/**
* Where to find .dot template files. Must end in a "/" if a value is specified.
* @var string
* @access public
*/
var $path_dot = "";
/**
* Where to find .doc files for appending. Must end in a "/" if a value is specified.
* @var string
* @access public
*/
var $path_doc = "";
/**
* Where the new file is to be saved. Must end in a "/" if a value is specified
* @var string
* @access public
*/
var $path_save = "";
/**
* Word template used to generate base document. Read-only
* @var string
* @access public
*/
var $template = "";
/**
* Filename of saved document. Empty til document has been saved. Read-only
* @var string
* @access public
*/
var $filename = "";
/**
* Diagnostic error message containing reason for failure. Read-only
* @var string
* @access public
*/
var $error_msg = "";
/**
* Word COM object
* @var object
* @access private
*/
var $word;
/**
* Holds search and replaces til ready for processing
* @var array
* @access private
*/
var $fields = array();
/**
* Constructor
*
* @param string $t - the template file to use. Empty if a blank document is to be generated
*/
function wd97template($t) {
$this->template = $t;
} // wd97template
/**
* Build up list of field subsitutions.
*
* Note that no other action is carried out here - use process() once the list is complete.
* It is possible to repeatedly carry out several assigns, followed by process()es.
*
* @access public
* @param array $a - associative array of fieldnames and values to be assigned, eg "FORENAME" => "Peter"
* @return void
*/
function assign($a) {
while (list($var, $val)=each($a)) {
$this->fields[$var]=stripslashes($val);
}
}
/**
* Creates the word instance ready for processing
*
* @access public
* @return boolean If false, error_msg has diagnostic
*/
function create() {
$res=true;
if (!$this->word=new COM("word.application")) { // For DCOM - add the server name as 2nd parameter (not tested)
$this->error_msg = "Cannot start Word for you";
return false;
}
$fp = $this->path_dot . $this->template;
if (!file_exists($fp)) {
$this->error_msg = "Could not find template file ".$fp;
return false;
}
if (!$this->word->Documents->Add($fp)) {
$this->error_msg = "Could create word file from ".$fp;
return false;
}
$this->word->visible = 1; // Makes no difference, but left in cos its in all the examples
return true;
} // create
// THE FOLLOWING FUNCTIONS DEPEND ON THE EXISTENCE OF A VALID OBJECT IN $this->word
// - ie that the ->create() method has been called.
/**
* Used for misc formatting actions
*
* Each action is performed in order, at the current cursor position
* Which is normally the file end.
* Unknown actions are ignored.
*
* DEPENDS ON THE EXISTENCE OF A VALID OBJECT IN $this->word
*
* @access public
* @param array $fmt List of instructions eg (array( "Orientation" => ??, "InsertBreak" => ??));
* @return void
*/
function format($fmt) {
$this->moveend();
reset($fmt);
while (list($k,$v) = each($fmt)) {
switch($k) {
case "InsertBreak":
$this->word->Selection->InsertBreak($v); // eg wdSectionBreakNextPage
break;
case "PageOrientation":
$this->word->Selection->MoveRight();
$oSel = $this->word->Selection;
$oSel->PageSetup->Orientation = $v;
break;
default:
}
}
}
/**
* Appends file to current document
*
* Leaves cursor at *end* of inserted file
*
* @access public
* @param string $f filename of the word document to be appended
* @return boolean If false, error_msg has diagnostic
*/
function appendfile($f) {
$fp = $this->path_doc.$f;
if ( !file_exists($fp) ) {
$this->error_msg = "Append file $fp does not exist";
return false;
}
$oDoc = $this->word->ActiveDocument;
$iEnd = $oDoc->Content->End - 1;
$oEndRange = $oDoc->Range($iEnd,$iEnd);
$oEndRange->InsertFile($fp);
$this->moveend();
return true;
} // appendfile
/**
* Carry out the replacement of fieldnames
*
* List of assigned fields is cleared.
*
* @access public
* @return void
*/
function process() {
$oFind = $this->word->ActiveDocument->Content->Find;
//Corresponding VBA is:
//expression.Execute(FindText, MatchCase, MatchWholeWord, MatchWildcards, MatchSoundsLike, MatchAllWordForms,
// Forward, Wrap,Format, ReplaceWith, Replace)
while (list($var, $val)=each($this->fields)) {
$oFind->Execute("{".$var."}", true, true, false, false, false,
true, true,false, $val, wdReplaceAll);
}
$this->fields = array(); // Clear out s&r ready for next time
} // process
/**
* Save file, deleting any previous copy
*
* To Do:
* Create backup copy before write.
*
* @param string $f full word document to be saved (needs ".doc")
*
* @access public
* @return boolean
*/
function saveas($f) {
if ( file_exists($this->path_save.$f) ) {
if ( !unlink($this->path_save.$f) ) {
$this->error_msg = "Could not delete previous versions of $f";
return false;
}
}
$this->word->ActiveDocument->SaveAs($this->path_save.$f);
$this->filename = $f;
return true;
} // end saveAs
/**
* Moves selection to file-end (for formatting and after appends).
*
* @access private
* @return void
*/
function moveend() {
$this->word->Selection->MoveEnd(wdStory);
$this->word->Selection->MoveRight();
}
/**
* Gets rid of Word process on server
*
* MUST BE CALLED otherwise the process will sit on the server forever.
*
* @access public
* @return void
*/
function destroy() {
$this->word->Quit();
} // destroy
} // end class
?>