Login   Register  
PHP Classes
elePHPant
Icontem

File: tbs_plugin_excel.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Skrol29  >  TinyButStrong plug-in for Excel  >  tbs_plugin_excel.php  >  Download  
File: tbs_plugin_excel.php
Role: Class source
Content type: text/plain
Description: the plug-in
Class: TinyButStrong plug-in for Excel
Generate Excel spreadsheets using template plug-in
Author: By
Last change: - Works with TBS version 3.6.2 or higher and with PHP 5.
- Possibility to save the result as a file.
- Possibility to retrieve the result in a PHP string.
- Avoid the output if a TBS error occurs.
- Fixed bug: Warning: Parameter 4 to clsTbsExcel::BeforeMergeBlock() expected to be a reference, value given [...]
- Fixed bug: Strict Standards: call_user_func() expects parameter 1 to be a valid callback, non-static method clsTbsExcel::f_XmlConv() should not be called statically in [...]
Date: 3 years ago
Size: 12,622 bytes
 

Contents

Class file image Download
<?php

/*
********************************************************
TinyButStrong plug-in: Excel Spreadsheets
Version 1.1.0, on 2011-02-03, by Skrol29, for TBS version >= 3.6.2
********************************************************
*/

// Name of the class is a keyword used for Plug-In authentication. So i'ts better to save it into a constant.
define('TBS_EXCEL','clsTbsExcel');
define('TBS_EXCEL_FILENAME', 'clsTbsExcel.FILENAME'); // deprecated command (=1)
define('TBS_EXCEL_DOWNLOAD',1); // deprecated command (=2) & Render option (by default) = TBS_OUTPUT
define('TBS_EXCEL_INLINE',4);   // deprecated command (=3) & Render option (do not use value 2 wich is reserved for TBS_EXIT)
define('TBS_EXCEL_FILE',8);     // Render option
define('TBS_EXCEL_STRING',16);   // Render option

class clsTbsExcel {

	// TBS events -----------------------------

	function OnInstall() {
		$this->Version = '1.1.0'; // Version can be displayed using [onshow..tbs_info] since TBS 3.2.0
		// Constants for the plug-in
		$this->TypeLst  = array('xlNum'=>'Number', 'xlDT'=>'DateTime', 'xlStr'=>'String', 'xlErr'=>'Error', 'xlBoo'=>'Boolean');
		$this->TypeLst2 = array('number'=>'Number', 'date'=>'DateTime', 'string'=>'String', 'error'=>'Error', 'boolean'=>'Boolean');
		// Usefulle properies
		$this->Oldies_FileName = '';
		$this->TemplateFileName = '';
		return array('OnCommand','BeforeLoadTemplate','AfterShow','OnOperation','BeforeMergeBlock','AfterMergeBlock','OnCacheField');
	}

	function OnCommand($Cmd,$Value='') {
		if ($Cmd==TBS_EXCEL_FILENAME) { // deprecated, compatibility with version 1.0
			// Change file name
			$this->Oldies_FileName = $Value;
		} elseif ($Cmd==TBS_EXCEL_DOWNLOAD) { // deprecated, compatibility with version 1.0
			// Force output to download file
			$this->TBS->Render = TBS_EXCEL_DOWNLOAD;
		} elseif ($Cmd==TBS_EXCEL_INLINE) { // deprecated, compatibility with version 1.0
			// Enables output to display inline (Internet Exlorer only)
			$this->TBS->Render = TBS_EXCEL_INLINE;
		}
	}

	function BeforeLoadTemplate(&$File, &$Charset) {
		if ($this->TemplateFileName==='') $this->TemplateFileName = $File;
		if ($Charset==='') $this->TBS->LoadTemplate('', array(&$this,'ConvXmlUtf8')); // Define the function for string conversion
	}

	function OnOperation($FieldName,&$Value,&$PrmLst,&$Source,$PosBeg,$PosEnd,$Loc) {
		if (isset($this->TypeLst[$PrmLst['ope']])) {
			if (!isset($Loc->xlType)) $this->tag_ChangeCellType($Source,$Loc,$this->TypeLst[$PrmLst['ope']]);
		} elseif ($PrmLst['ope']==='xlPushRef') {
			$this->tag_ChangeFormula($Source,$Loc,$Value,true);
		}
	}

	function OnCacheField($BlockName,&$Loc,&$Txt,$PrmProc) {

		if (isset($Loc->PrmLst['ope'])) {
			// in this event, ope parameter is not exploded yet
			$ope_lst = explode(',', $Loc->PrmLst['ope']);
			$ope_att = false;
			foreach ($ope_lst as $ope) {
				$ope=trim($ope,' ');
				if (isset($this->TypeLst[$ope])) $ope_att = $this->TypeLst[$ope];
			}
			// if a the cell type must be modified, then we add a new TBS field for changing the attribute value
			if ($ope_att!==false) {
				$this->tag_ChangeCellFormat($Loc, $ope_att);
				$newfield = '['.$BlockName.';att=Data#ss:Type;if 1=1;then '.$ope_att.']';
				$Txt = substr_replace($Txt, $newfield, $Loc->PosEnd+1,0); // the new field is added after the current field so it will be scanned by TBS
				$Loc->xlType = true; // avoid a double process of such ope values
			}
		}

	}

	function BeforeMergeBlock(&$TplSource,&$BlockBeg,&$BlockEnd,$PrmLst,&$DataSrc,&$LocR) {
	/* Manage attribute ssIndex.
	   Attribute ssIndex can be put by Excel on the first <Row> and <Cell> item of a <Table> element.
	   But this attribute must be put only once per series, it must not be repeated on next items when it is merged for a block.
	   So if we have it (it must be on the first item) we save it, delete it, and then and add it only for the first item merged (see AfterMergeBlock).
	*/
		$this->ssIndex = false;
		if ($LocR->SectionNbr>0) {
			$Src1 =& $LocR->SectionLst[1]->Src ;
			// Check if the first block begins with Row or Cell.
			$Start = '';
			if (substr($Src1,0,4)==='<Row')  $Start='<Row' ;
			if (substr($Src1,0,5)==='<Cell') $Start='<Cell' ;
			if ($Start!=='') {
				// The attribute ss:Index can be there.
				// Search for the end of the tag
				$p = strpos($Src1,'>');
				if ($p!==false) {
					$tag = substr($Src1,0,$p+1);
					// Searche for attribute ss:Index
					$p = strpos($tag,'ss:Index');
					if ($p!==false) {
						// ss:Index is found, we have to save it and take it off from the block's source
						$p1 = strpos($tag,'"',$p);
						if ($p1!==false) {
							$p2 = strpos($tag,'"',$p1+1);
							if ($p2!==false) {
								$len = $p2 - $p + 1;
								$this->ssIndex = true;
								$this->ssIndexStart = $Start;
								$this->ssIndexSource = substr($Src1,$p,$len);
								$Src1 = substr_replace($Src1,str_repeat(' ',$len),$p,$len);
							}
						}
					}
				}
			}
		}
	}

	function AfterMergeBlock(&$Buffer,&$DataSrc,&$LocR) {
		// Replace attribute ss:Index if necessary, only one time for the block.
		if ($this->ssIndex) {
			$len = strlen($this->ssIndexStart);
			if (substr($Buffer,0,$len)===$this->ssIndexStart) {
				$Buffer = substr_replace($Buffer,' '.$this->ssIndexSource,$len,0);
			}
			$this->ssIndex = false;
		}
	}

	function AfterShow(&$Render, $File='') {

		$TBS =& $this->TBS;

		// Delete optional XML attributes that could become invalide after the merge
		$this->tag_DelOptionalTableAtt();

		if ( ($TBS->ErrCount>0) && (!$TBS->NoErr) ) {
			$TBS->meth_Misc_Alert('Show() Method', 'The output is cancelled by the Excel plugin because at least one TBS error has occured.');
			exit;
		}

		if ($File==='') {
			if ($this->Oldies_FileName==='') {
				if ($this->TemplateFileName==='') {
					$File = 'result_'.date('Y-m-d').'.xml';
				} else {
					$File = basename($this->TemplateFileName);
				}
			} else {
				$File = $this->Oldies_FileName;
			}
		}

		// Makes a download instead of displaying the result.
		if (($Render & TBS_OUTPUT)==TBS_OUTPUT) { // TBS_OUTPUT = TBS_EXCEL_DOWNLOAD
			// content downloaded
			$this->f_HttpHeader_Download($File);
		} elseif (($Render & TBS_EXCEL_INLINE)==TBS_EXCEL_INLINE) {
			// content displayed in the browser
			$this->f_HttpHeader_Inline($File);
			$Render = $Render - TBS_EXCEL_INLINE;
			if (($Render & TBS_OUTPUT)!=TBS_OUTPUT) $Render = $Render + TBS_OUTPUT; // needed for final output
		} elseif (($Render & TBS_EXCEL_FILE)==TBS_EXCEL_FILE) {
			// content saved in a file
			$hndl = fopen($File, 'w');
			fwrite($hndl, $this->TBS->Source);
			fclose($hndl);
		} elseif (($Render & TBS_EXCEL_STRING)==TBS_EXCEL_STRING) {
			// content returned in the TBS->Source property (nothing to do)
		}

		// the TBS::Show() method will then recover the process and perform the TBS_OUTPUT and TBS_EXIT options, if any

	}

	// --------------------------
	// Functions for internal job
	// --------------------------

	function ConvXmlOnly($Txt, $ConvBr) {
	// Used by TBS to convert special chars and new lines.
	  $x = htmlspecialchars($Txt);
	  if ($ConvBr) $this->ConvBr($x);
	  return $x;
	}

	function ConvXmlUtf8($Txt, $ConvBr) {
	// Used by TBS to convert special chars and new lines.
	  $x = htmlspecialchars(utf8_encode($Txt));
	  if ($ConvBr) $this->ConvBr($x);
	  return $x;
	}

	function f_HttpHeader_Download($FileName) {

		header ('Pragma: no-cache');
		//  header ('Content-type: application/x-msexcel');
		header ('Content-Type: application/vnd.ms-excel');
		header ('Content-Disposition: attachment; filename="'.$FileName.'"');

		header('Expires: 0');
		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
		header('Cache-Control: public');
		header('Content-Description: File Transfer');

		header('Content-Transfer-Encoding: binary');
		header('Content-Length: '.strlen($this->TBS->Source));

	}

	function f_HttpHeader_Inline($FileName) {

		header('Content-Type: application/x-msexcel; name="'.$FileName.'"');
		header('Content-Disposition: inline; filename="'.$FileName.'"');

	}

	function tag_ChangeCellType(&$Txt, $Loc, $Type) {
	// Change the cell type. This function assumes that the current cell has a type set to String. String type is expected since the cell contains a TBS tag.
		if ($Type==='String') return true;
		$t0 = clsTinyButStrong::f_Xml_FindTagStart($Txt,'Data',true,$Loc->PosBeg,false,true);
		if ($t0===false) return false; // error in the XML structure
		$te = strpos($Txt, '>', $t0);
		if ( ($te===false) || ($te>$Loc->PosBeg) ) return false; // error in the XML structure
		$len = $te - $t0 + 1;
		$tag = substr($Txt, $t0, $len);
		$len = strlen($tag);
		$att = ' ss:Type="String"';
		$att2 = ' ss:Type="'.$Type.'"';
		$tag = str_replace($att, $att2, $tag);
		$Txt = substr_replace($Txt, $tag, $t0, $len);
		$diff = strlen($tag) - $len;
		if ($diff!==0) {
			$Loc->PosBeg += $diff;
			$Loc->PosEnd += $diff;
		}
		$this->tag_ChangeCellFormat($Loc, $Type);
		return true;
	}

	function tag_ChangeCellFormat(&$Loc, $Type) {
		if ($Type==='DateTime') {
			$Loc->PrmLst['frm'] = 'yyyy-mm-ddThh:nn:ss';
			// activate the FRM mode
			$Loc->ConvMode = 0;
			$Loc->ConvProtect = false;
		}
	}

	function tag_ChangeFormula(&$Txt,&$Loc,&$Value,$First) {
		// The process assumes that the TBS is embeded into a N("") function

		if (isset($Loc->xlExend)) {

			if (!$Loc->xlExend) return false;

		} else {

			$Loc->xlExend = false;

			// So we first search for the begining of the TBS expression. Going backward.
			$p = $Loc->PosBeg - 1;
			$cont = true;
			$exp_n = false;   // true if N is met
			$exp_beg = false; //
			do {
				$x = $Txt[$p];
				if ($p<2) {
					$cont = false;
				} elseif ($x==='"') {
					$cont = false; // end of the formula
				} elseif ($x==='(') { // begining of the function's arguments
					$exp_n = true;
				} elseif (($x==='+') or ($x==='&')) { // The expression can be added with + or & (wich is saved as &amp;)
					if ($exp_n)	{
						$exp_beg = $p;
						$cont = false;
					}
				}
				if ($cont) $p--;
			} while ($cont);
			if ($exp_beg===false) return false;

			// Search for the end of the TBS expression.
			$frm_end = strpos($Txt,'"',$Loc->PosEnd+1);
			if ($frm_end===false) return false;
			$exp_end = strpos($Txt,')',$Loc->PosEnd+1);
			if ($exp_end===false) return false;
			if ($exp_end>$frm_end) return false;

			// Now we searching backard, the relative cell
			$cont = true;
			$br_o = false;    // position of [
			$br_c = false;    // position of ]
			$p = $exp_beg - 1;
			do {
				$x = $Txt[$p];
				if ($p<2) {
					$cont = false;
				} elseif ($x===']') {
					if ($br_o===false) $br_c = $p;
				} elseif ($x==='[') {
					if ($br_c!==false) $br_o = $p;
					$cont=false;
				} elseif ($x==='"') {
					$cont=false;
				}
				if ($cont) $p--;
			} while ($cont);
			if ($br_o===false) return false;

			// Calculate the relative index
			$x = intval(substr($Txt,$br_o+1,$br_c-$br_o-1));
			if ($x==0) return false;

			// Save information in the locator, useful for cached locators
			$Loc->xlVal = $x;
		  $Loc->xlExtraStr = substr($Txt,$br_c,$exp_beg-$br_c);
			$Loc->xlExend = true;
			$Loc->PosBeg = $br_o + 1;
			$Loc->PosEnd = $exp_end;

			$Loc->ConvMode = -1; // No contents conversion

		}

		// Calculate the new index
		$v = intval($Value);
		$x = $Loc->xlVal;
		if ($x!=0) $x = $x + $v - 1;

		// Replace the index value
		$Value = strval($x).$Loc->xlExtraStr;

	}

	function tag_DelOptionalTableAtt() {
	// Two Table attributes give the size of the zone, this zone may be extended after a MergeBlock()
	// Hopefully, those attributes are optional, so we delete them.
		$Txt =& $this->TBS->Source;
		$att_lst = array('ss:ExpandedColumnCount', 'ss:ExpandedRowCount');
		$Pos = 0;
		while ( ($Loc=clsTinyButStrong::f_Xml_FindTag($Txt,'Table',true,$Pos,true,false,true,true))!==false ) {
			foreach ($att_lst as $att) {
				// delete the attributes by replacing them with spaces
				$att = strtolower($att); // The TBS method does turn attributes anmes into lowercase.
				if (isset($Loc->PrmPos[$att])) {
					$p = $Loc->PrmPos[$att];
					$n = $p[3] - $p[0] + 1;
					$Txt = substr_replace($Txt, str_repeat(' ',$n), $p[0], $n);
				}
			}
			$Pos = $Loc->PosEnd+1;
		}

	}

}