function mergeODT($source_file, $merged_file)
 {
     $xml_filename = 'content.xml';
     require_once 'include/odf_tools.class.php';
     $content = ODF_Tools::getXML($source_file, $xml_filename);
     if (empty($content)) {
         trigger_error('Could not find content within this ' . $extension . ' file');
         return;
     }
     $HEADER_END = '</text:sequence-decls>';
     $FOOTER_START = '</office:text>';
     $middle_start_pos = strpos($content, $HEADER_END) + strlen($HEADER_END);
     $middle_end_pos = strpos($content, $FOOTER_START);
     if (NULL === $middle_start_pos || NULL === $middle_end_pos) {
         trigger_error('Cannot locate body content of the file');
         return;
     }
     $middle_template = substr($content, $middle_start_pos, $middle_end_pos - $middle_start_pos);
     $header = substr($content, 0, $middle_start_pos);
     $footer = substr($content, $middle_end_pos);
     $merged_middle = '';
     foreach ($this->getMergeData() as $id => $row) {
         if (empty($row)) {
             continue;
         }
         $this_middle = $middle_template;
         foreach ($row as $k => $v) {
             $this_middle = str_replace('%' . strtoupper($k) . '%', ODF_Tools::odfEntities(trim($v)), $this_middle);
         }
         $merged_middle .= $this_middle;
     }
     $merged_file = dirname($source_file) . '/jethro_merged_' . time() . session_id();
     copy($source_file, $merged_file);
     ODF_Tools::setXML($merged_file, $header . $merged_middle . $footer, $xml_filename);
 }
 static function replaceKeywords($filename, $replacements, $xml_filenames = NULL)
 {
     if (is_null($xml_filenames)) {
         $xml_filenames = array('content.xml', 'styles.xml');
     }
     foreach ($xml_filenames as $xml_filename) {
         $xml = ODF_Tools::getXML($filename, $xml_filename);
         foreach ($replacements as $k => $v) {
             $xml = str_replace('%' . strtoupper($k) . '%', ODF_Tools::odfEntities(trim($v)), $xml);
         }
         ODF_TOOLS::setXML($filename, $xml, $xml_filename);
     }
 }
 function processPopulate()
 {
     foreach ($this->_dirs['populate'] as $dir) {
         chdir($dir);
         if (empty($_POST['replacements'])) {
             // Get ready to print the replacements form
             foreach ($this->_congregations as $congid => &$congregation) {
                 $service = Service::findByDateAndCong($this->_service_date, $congid);
                 if (empty($service)) {
                     add_message('No service found for congregation ' . $congregation['name'] . ' on ' . $this->_service_date, 'warning');
                     unset($this->_congregations[$congid]);
                     continue;
                 }
                 $next_service = Service::findByDateAndCOng(date('Y-m-d', strtotime($this->_service_date . ' +1 week')), $congid);
                 $basename = $this->_service_date . '_' . $congregation['meeting_time'];
                 if (is_file($dir . '/' . $basename . '.odt')) {
                     $odf_filename = $dir . '/' . $basename . '.odt';
                 } else {
                     if (is_file($dir . '/' . $basename . '.odp')) {
                         $odf_filename = $dir . '/' . $basename . '.odp';
                     } else {
                         add_message('No file found for ' . $basename . ' in ' . $dir, 'warning');
                         continue;
                     }
                 }
                 $odf_content = ODF_Tools::getXML($odf_filename);
                 if (empty($odf_content)) {
                     continue;
                 }
                 $congregation['filenames'][] = basename($dir) . ' / ' . basename($odf_filename);
                 $keywords = ODF_Tools::getKeywords($odf_filename);
                 foreach ($keywords as $keyword) {
                     $keyword = strtoupper($keyword);
                     if (isset($_POST['replacements'][$congid][$keyword])) {
                         $this->_replacements[$congid][$keyword] = $_POST['replacements'][$congid][$keyword];
                     } else {
                         if (0 === strpos($keyword, 'NEXT_SERVICE_')) {
                             if (!empty($next_service)) {
                                 $service_field = strtolower(substr($keyword, strlen('NEXT_SERVICE_')));
                                 $this->_replacements[$congid][$keyword] = $next_service->getValue($service_field);
                                 if ($service_field == 'date') {
                                     // make a short friendly date
                                     $this->_replacements[$congid][$keyword] = date('j M', strtotime($this->_replacements[$congid][$keyword]));
                                 }
                             } else {
                                 add_message("NEXT_SERVICE_ keyword could not be replaced because no next service was found for " . $congregation['name'], 'warning');
                                 $this->_replacements[$congid][$keyword] = '';
                             }
                         } else {
                             if (0 === strpos($keyword, 'CONGREGATION_')) {
                                 $cong_field = strtolower(substr($keyword, strlen('CONGREGATION_')));
                                 $this->_replacements[$congid][$keyword] = $congregation[$cong_field];
                             } else {
                                 $this->_replacements[$congid][$keyword] = $service->getKeywordReplacement($keyword);
                             }
                         }
                     }
                 }
             }
         } else {
             // do the replacements
             $this->_replacements = $_POST['replacements'];
             foreach ($this->_congregations as $congid => $details) {
                 $basename = $this->_service_date . '_' . $details['meeting_time'];
                 if (is_file($dir . '/' . $basename . '.odt')) {
                     $odf_filename = $basename . '.odt';
                 } else {
                     if (is_file($dir . '/' . $basename . '.odp')) {
                         $odf_filename = $basename . '.odp';
                     } else {
                         continue;
                     }
                 }
                 $output_odf_filename = 'POPULATED_' . $odf_filename;
                 if (file_exists($dir . '/' . $output_odf_filename)) {
                     if (!unlink($output_odf_filename)) {
                         trigger_error('Cannot write to ' . $output_odf_filename . ' - is the file in use?');
                         continue;
                     }
                 }
                 copy($dir . '/' . $odf_filename, $dir . '/' . $output_odf_filename);
                 ODF_Tools::replaceKeywords($dir . '/' . $output_odf_filename, $this->_replacements[$congid]);
                 chmod($dir . '/' . $output_odf_filename, fileperms($dir . '/' . $odf_filename));
                 $this->_generated_files[] = basename($dir) . ' / ' . $output_odf_filename;
             }
             $this->_addGeneratedFilesMessage();
         }
     }
 }