594 lines
16 KiB
PHP
594 lines
16 KiB
PHP
<?php
|
|
|
|
defined('LAYOUTER_HTML_MODE') || define ( 'LAYOUTER_HTML_MODE','0' );
|
|
class ColProperty {
|
|
public static $LEFT = 0;
|
|
public static $RIGHT = 1;
|
|
public static $CENTER = 2;
|
|
public static $COMPLETE = 3;
|
|
|
|
public static $NORMAL = 0;
|
|
public static $HIGH = 1;
|
|
public static $WIDE = 2;
|
|
public static $WIDEHIGH = 3;
|
|
|
|
public static $HTML = 0;
|
|
public static $PR = 1;
|
|
|
|
public $length = -1;
|
|
|
|
private static $freeChars = " ";
|
|
|
|
public static $LF = 10;
|
|
private static $escpos_doubleheight = array(27, 33, 16);
|
|
private static $escpos_doublewidth = array(27, 33, 32);
|
|
private static $escpos_doubleheightwidth = array(27, 33, 48);
|
|
private static $escpos_double_off = array(27, 33, 0);
|
|
|
|
function __construct($aColSpec) {
|
|
if ($aColSpec != "") {
|
|
$lengthOfACell = trim($aColSpec);
|
|
$this->length = intval($lengthOfACell);
|
|
if ($this->length < 0) {
|
|
$this->length = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setLength($len) {
|
|
if ($len< 0) {
|
|
$this->length = 0;
|
|
} else {
|
|
$this->length = $len;
|
|
}
|
|
}
|
|
|
|
public function render($varcontent,$just,$label,$varstyle,$useColonAfterLabel) {
|
|
$endOfLabel = "";
|
|
if ($useColonAfterLabel) {
|
|
$endOfLabel = ":";
|
|
}
|
|
if (is_null($varcontent)) {
|
|
$text = $label;
|
|
} else {
|
|
$text = $varcontent;
|
|
if ($label != "") {
|
|
$text = $label . $endOfLabel . $varcontent;
|
|
}
|
|
}
|
|
$textInCp437 = self::asciiEncodeStringTo437($text);
|
|
$contentLength = 0;
|
|
$factor = 1;
|
|
if (($varstyle == self::$NORMAL) || ($varstyle == self::$HIGH)) {
|
|
$contentLength = strlen($textInCp437);
|
|
$factor = 1;
|
|
} else if ($varstyle == self::$WIDE) {
|
|
$contentLength = strlen($textInCp437) * 2;
|
|
$factor = 2;
|
|
} else if ($varstyle == self::$WIDEHIGH) {
|
|
$contentLength = strlen($textInCp437) * 2;
|
|
$factor = 2;
|
|
}
|
|
|
|
if ($just == ColProperty::$COMPLETE) {
|
|
if ($contentLength > $this->length) {
|
|
$textLines = array();
|
|
$remaingText = $text;
|
|
while (strlen($remaingText) > 0) {
|
|
$textToSplit = $remaingText;
|
|
$maxLength = strlen($textToSplit) * $factor;
|
|
$cutLength = min($maxLength,$this->length / $factor);
|
|
$textLines[] = substr($textToSplit,0,$cutLength);
|
|
$remaingText = substr($textToSplit,$cutLength);
|
|
}
|
|
$text = implode("\n", $textLines);
|
|
}
|
|
return $this->textOutDueToFont(0, $text, 0, $varstyle);
|
|
}
|
|
$textlen = $contentLength;
|
|
if ($contentLength > $this->length) {
|
|
$text = substr($text, 0, $this->length / $factor);
|
|
$textlen = $this->length;
|
|
}
|
|
|
|
$freeSpace = $this->length - $textlen;
|
|
|
|
$fillstart = 0;
|
|
$fillend = $freeSpace;
|
|
if ($just == self::$RIGHT) {
|
|
$fillstart = intval($freeSpace);
|
|
$fillend = 0;
|
|
} else if ($just == self::$CENTER) {
|
|
$fillstart = intval($freeSpace / 2);
|
|
$fillend = $freeSpace - $fillstart;
|
|
}
|
|
$out = $this->textOutDueToFont($fillstart, $text, $fillend, $varstyle);
|
|
|
|
return $out;
|
|
}
|
|
|
|
private function textOutDueToFont($fillspacestart,$text,$fillspaceend,$namestyle) {
|
|
$start = substr(self::$freeChars, 0,$fillspacestart);
|
|
$end = substr(self::$freeChars, 0,$fillspaceend);
|
|
$htmltxt = '';
|
|
$fillchar = '';
|
|
if (($namestyle == self::$WIDE) || ($namestyle == self::$WIDEHIGH)) {
|
|
$fillchar = ' ';
|
|
}
|
|
for ($i=0;$i<strlen($text);$i++) {
|
|
$htmltxt .= $text[$i] . $fillchar;
|
|
}
|
|
$htmltxt = $start . $htmltxt . $end;
|
|
|
|
$prbytes = array();
|
|
$textInCp437 = self::asciiEncodeStringTo437($text);
|
|
$fontctrlstart = array();
|
|
$fontctrlend = array();
|
|
if ($namestyle == self::$WIDE) {
|
|
$fontctrlstart = self::$escpos_doublewidth;
|
|
$fontctrlend = self::$escpos_double_off;
|
|
} else if ($namestyle == self::$HIGH) {
|
|
$fontctrlstart = self::$escpos_doubleheight;
|
|
$fontctrlend = self::$escpos_double_off;
|
|
} else if ($namestyle == self::$WIDEHIGH) {
|
|
$fontctrlstart = self::$escpos_doubleheightwidth;
|
|
$fontctrlend = self::$escpos_double_off;
|
|
}
|
|
|
|
for ($i=0;$i<$fillspacestart;$i++) {
|
|
$prbytes[] = 32;
|
|
}
|
|
foreach ($fontctrlstart as $b) {
|
|
$prbytes[] = $b;
|
|
}
|
|
for ($i=0;$i<strlen($textInCp437);$i++) {
|
|
//$prbytes[] = $textInCp437[$i];
|
|
$prbytes[] = strval(ord(strval($textInCp437[$i])));
|
|
}
|
|
foreach ($fontctrlend as $b) {
|
|
$prbytes[] = $b;
|
|
}
|
|
for ($i=0;$i<$fillspaceend;$i++) {
|
|
$prbytes[] = 32;
|
|
}
|
|
return array("html" => $htmltxt,"printer" => $prbytes);
|
|
}
|
|
|
|
private static function detect_encoding($string, $enc=null) {
|
|
static $list = array('utf-8', 'iso-8859-1', 'windows-1251');
|
|
|
|
foreach ($list as $item) {
|
|
$sample = iconv($item, $item, $string);
|
|
if (md5($sample) == md5($string)) {
|
|
if ($enc == $item) { return true; } else { return $item; }
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
private static function asciiEncodeStringTo437($string)
|
|
{
|
|
$sourceEncoding = self::detect_encoding($string);
|
|
$destinationEncoding = 'CP437'; // Extended ASCII - Codepage 437
|
|
$string = iconv($sourceEncoding, $destinationEncoding, $string);
|
|
return $string;
|
|
}
|
|
|
|
public function log() {
|
|
return "COL(" . $this->length . ")";
|
|
}
|
|
|
|
}
|
|
|
|
class TemplateTable {
|
|
// col properties of each col
|
|
private $cols;
|
|
// total space for each line
|
|
private $totalSpace;
|
|
|
|
function __construct($tabspecline,$total) {
|
|
$this->totalSpace = $total;
|
|
// something like TAB:links-3:recht:mittig:5
|
|
$this->cols = array();
|
|
$colParts = explode(":",$tabspecline);
|
|
// remove "TAB"
|
|
array_shift($colParts);
|
|
foreach($colParts as $aColSpec) {
|
|
// "links-4" or "mittig"
|
|
$colProperty = new ColProperty($aColSpec);
|
|
$this->cols[] = $colProperty;
|
|
}
|
|
// now check number of elements without length
|
|
$colsWithUnSpecifiedLength = 0;
|
|
$colsTotalLength = 0;
|
|
foreach($this->cols as $aCol) {
|
|
if ($aCol->length == -1) {
|
|
$colsWithUnSpecifiedLength++;
|
|
} else {
|
|
$colsTotalLength += $aCol->length;
|
|
}
|
|
}
|
|
$roomToDistribute = $this->totalSpace - $colsTotalLength;
|
|
$eachCol = intval($roomToDistribute / max($colsWithUnSpecifiedLength,1));
|
|
|
|
$assignedCols = 0;
|
|
foreach($this->cols as $aCol) {
|
|
if ($aCol->length == -1) {
|
|
if (($assignedCols+1) == $colsWithUnSpecifiedLength) {
|
|
// rest
|
|
$aCol->setLength($roomToDistribute - $eachCol * $assignedCols);
|
|
} else {
|
|
$aCol->setLength($eachCol);
|
|
$assignedCols++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getColSpec($colNo) {
|
|
return $this->cols[$colNo];
|
|
}
|
|
|
|
public function log() {
|
|
$log = "";
|
|
foreach($this->cols as $aCol) {
|
|
$log .= $aCol->log() . " ";
|
|
}
|
|
return $log;
|
|
}
|
|
}
|
|
|
|
class TicketEntry implements JsonSerializable {
|
|
private $typeofentry;
|
|
private $content;
|
|
|
|
function __construct($theType,$theContent) {
|
|
$this->typeofentry = $theType;
|
|
$this->content = $theContent;
|
|
}
|
|
|
|
public function jsonSerialize()
|
|
{
|
|
$c = $this->content;
|
|
if ($this->typeofentry == "bytes") {
|
|
$c = implode(',',$this->content);
|
|
}
|
|
return
|
|
[
|
|
'typeofentry' => $this->typeofentry,
|
|
'content' => $c
|
|
];
|
|
}
|
|
}
|
|
|
|
class Layouter {
|
|
private static $outPr = array();
|
|
private static $outHtml = "";
|
|
|
|
private static $space = 40;
|
|
private static $curCol = 0;
|
|
private static $tableProperties;
|
|
|
|
public static function layoutTicket($template,$data,$printersize) {
|
|
self::$outPr = array();
|
|
self::$outHtml = "";
|
|
self::$space = $printersize;
|
|
|
|
$lines = explode("\n", $template);
|
|
self::loop($lines,$data);
|
|
|
|
if (LAYOUTER_HTML_MODE == 1) {
|
|
return array("html" => self::$outHtml, "printer" => self::$outHtml);
|
|
} else {
|
|
return array("html" => self::$outHtml, "printer" => self::$outPr);
|
|
}
|
|
}
|
|
|
|
private static function loop($lines, $data) {
|
|
|
|
$skippinguntil = null;
|
|
|
|
foreach ($data as $dataline) {
|
|
// iterate through lines- In case of loops the linenumber needs to be incereased inside the loop
|
|
$linenumber = 0;
|
|
|
|
while ($linenumber < count($lines)) {
|
|
$t = $lines[$linenumber];
|
|
$t = trim($t);
|
|
|
|
$lineHadContent = false;
|
|
if ($t != "") {
|
|
$pos = stripos($t,'if:');
|
|
if ($pos !== false) {
|
|
if (($pos >= 0) && ($pos <= 7)) {
|
|
$ifParts = explode(':',$t);
|
|
$itemToCheck = $ifParts[1];
|
|
$valueToCheck = $ifParts[2];
|
|
$realValue = $dataline[$itemToCheck];
|
|
if ($realValue != $valueToCheck) {
|
|
$skippinguntil = $itemToCheck;
|
|
++$linenumber;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
$pos = stripos($t,'fi:');
|
|
if ($pos !== false) {
|
|
if (($pos >= 0) && ($pos <= 7)) {
|
|
$endifParts = explode(':',$t);
|
|
$itemToCheck = $endifParts[1];
|
|
if ($itemToCheck == $skippinguntil) {
|
|
$skippinguntil = null;
|
|
++$linenumber;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_null($skippinguntil)) {
|
|
++$linenumber;
|
|
continue;
|
|
}
|
|
|
|
if (CommonUtils::startsWith($t,'#')) {
|
|
++$linenumber;
|
|
continue;
|
|
}
|
|
|
|
if (CommonUtils::startsWith($t, 'LOGO')) {
|
|
$ticketEntry = new TicketEntry("img", "1");
|
|
self::$outPr[] = $ticketEntry;
|
|
++$linenumber;
|
|
continue;
|
|
}
|
|
|
|
$pos = strpos($t,'START');
|
|
if ($pos !== false) {
|
|
if (($pos >= 0) && ($pos <= 7)) {
|
|
$loopDeclParts = explode(':',$t);
|
|
$marker = trim($loopDeclParts[1]);
|
|
$loopLines = self::collectLinesOfLoop($lines,$linenumber+1,$marker);
|
|
$linesToSkip = count($loopLines) + 2;
|
|
self::loop($loopLines, $dataline[$marker]);
|
|
$linenumber += $linesToSkip;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$outContent = array();
|
|
$theType = "";
|
|
$parts = self::getParts($t);
|
|
foreach($parts as $element) {
|
|
$elemWithoutBrackets = substr($element, 1, strlen($element)-2);
|
|
|
|
$partEval = self::evalElem($elemWithoutBrackets,$dataline);
|
|
$lineHadContent |= $partEval['linehascontent'];
|
|
self::$outHtml .= $partEval["html"];
|
|
$theType = $partEval['typeofentry'];
|
|
if ($partEval['typeofentry'] == "bytes") {
|
|
$outContent = array_merge($outContent,$partEval['bytes']);
|
|
} else {
|
|
$outContent = $partEval['bytes']; // may be also string for image reference
|
|
}
|
|
}
|
|
if ($lineHadContent) {
|
|
$ticketEntry = new TicketEntry($theType, $outContent);
|
|
self::$outPr[] = $ticketEntry;
|
|
}
|
|
} else {
|
|
self::$outPr[] = new TicketEntry("bytes",array(ColProperty::$LF));
|
|
$lineHadContent = true;
|
|
}
|
|
if ($lineHadContent) {
|
|
self::$outHtml .= "<br>";
|
|
self::$curCol = 0;
|
|
}
|
|
++$linenumber;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static function collectLinesOfLoop($lines,$linenumber,$marker) {
|
|
$looplines = array();
|
|
while ($linenumber < count($lines)) {
|
|
$aLine = $lines[$linenumber];
|
|
$pos = stripos($aLine,'end:'.$marker);
|
|
if ($pos !== false) {
|
|
if (($pos >= 0) && ($pos < 5)) {
|
|
return $looplines;
|
|
} else {
|
|
$looplines[] = $aLine;
|
|
}
|
|
} else {
|
|
$looplines[] = $aLine;
|
|
}
|
|
$linenumber++;
|
|
}
|
|
return $looplines;
|
|
}
|
|
|
|
private static function getCommaSeparatedValuesOfElem($text) {
|
|
$out = array();
|
|
$parts = explode(":", $text);
|
|
if (count($parts) > 1) {
|
|
$valsPart = $parts[1];
|
|
$out = explode(",",$valsPart);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
private static function evalElem($elemContent, $dataline) {
|
|
if (self::startsWith($elemContent, "TAB")){
|
|
self::setTableProperties($elemContent);
|
|
return array("bytes" => array(),"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
|
|
} else if (self::startsWith($elemContent, "RAWD")) {
|
|
$vals = self::getCommaSeparatedValuesOfElem($elemContent);
|
|
return array("bytes" => $vals,"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
|
|
} else if (self::startsWith($elemContent, "RAWH")) {
|
|
$vals = self::getCommaSeparatedValuesOfElem($elemContent);
|
|
$decVals = array();
|
|
foreach($vals as $v) {
|
|
$decVals[] = hexdec(strtolower($v));
|
|
}
|
|
return array("bytes" => $decVals,"html" => "", "linehascontent" => false,"typeofentry" => "bytes");
|
|
} else if (self::startsWith($elemContent, "LINIE")){
|
|
$parts = explode(":", $elemContent);
|
|
$charToUse = "-";
|
|
if (count($parts) > 1) {
|
|
$charToUse = $parts[1];
|
|
}
|
|
$fillLine = "";
|
|
$outbytes = array();
|
|
for ($i=0;$i<self::$space;$i++) {
|
|
$fillLine .= $charToUse;
|
|
$outbytes[] = ord($charToUse);
|
|
}
|
|
return array("bytes" => $outbytes,"html" => $fillLine, "linehascontent" => true,"typeofentry" => "bytes");
|
|
} else if (self::startsWith(strtolower ($elemContent), "qrcode")) {
|
|
$qrparts = explode(':', $elemContent);
|
|
$scale = 100;
|
|
if (count($qrparts) > 1) {
|
|
$scale = $qrparts[1];
|
|
}
|
|
$billid = $dataline["id"];
|
|
return array("bytes" => "2,$billid,$scale","html" => "php/contenthandler.php?module=bill&command=billqrcode&billid=$billid", "linehascontent" => true,"typeofentry" => "img");
|
|
} else if (self::startsWith(strtolower ($elemContent), "waiterphoto")) {
|
|
$parts = explode(':', $elemContent);
|
|
$scale = 100;
|
|
if (count($parts) > 1) {
|
|
$scale = $parts[1];
|
|
}
|
|
if (isset($dataline["userid"])) {
|
|
$userid = $dataline["userid"];
|
|
if (!is_null($userid) && (intval($userid) > 0)) {
|
|
return array("bytes" => "3,$userid,$scale","html" => "php/contenthandler.php?module=admin&command=getwaiterphotoforprint&userid=$userid", "linehascontent" => true,"typeofentry" => "img");
|
|
}
|
|
}
|
|
} else {
|
|
$parts = explode(":", $elemContent);
|
|
$placeholder = $parts[0];
|
|
$realElem = self::substPlaceholder($placeholder,$dataline);
|
|
$lines = explode("\n", $realElem);
|
|
if (count($lines) == 1) {
|
|
$colContent = self::evalOneElementOfALine($elemContent, $dataline);
|
|
} else {
|
|
// multiple lines
|
|
$colContent = array("html" => "","printer" => array());
|
|
$i = 0;
|
|
foreach($lines as $contentLine) {
|
|
$aDataLine = array($placeholder => $contentLine);
|
|
$newColContent = self::evalOneElementOfALine($elemContent, $aDataLine);
|
|
|
|
if (($i+1) < count($lines)) {
|
|
$bytes = array_merge($colContent["printer"],$newColContent["printer"],array(ColProperty::$LF));
|
|
$html = $colContent["html"] . $newColContent["html"] . "<br>";
|
|
} else {
|
|
$bytes = array_merge($colContent["printer"],$newColContent["printer"]);
|
|
$html = $colContent["html"] . "<br>" . $newColContent["html"];
|
|
}
|
|
|
|
$colContent = array("html" => $html,"printer" => $bytes);
|
|
|
|
++$i;
|
|
}
|
|
}
|
|
self::$curCol++;
|
|
|
|
return array("bytes" => $colContent["printer"],"html" => $colContent["html"], "linehascontent" => true, "typeofentry" => "bytes");
|
|
}
|
|
}
|
|
|
|
private static function evalOneElementOfALine($elemContent,$dataline) {
|
|
$parts = explode(":", $elemContent);
|
|
$placeholder = $parts[0];
|
|
$realElem = self::substPlaceholder($placeholder,$dataline);
|
|
if (!is_null($realElem) && ($realElem == "")) {
|
|
return array("html" => "","printer" => array());
|
|
}
|
|
|
|
$side = ColProperty::$LEFT;
|
|
if (count($parts) > 1) {
|
|
$just = trim($parts[1]);
|
|
|
|
if (($just == "links") || ($just == "left")) {
|
|
$side = ColProperty::$LEFT;
|
|
} else if (($just == "rechts") || ($just == "right")) {
|
|
$side = ColProperty::$RIGHT;
|
|
} else if (($just == "mittig") || ($just == "center")) {
|
|
$side = ColProperty::$CENTER;
|
|
} else if (($just == "komplett") || ($just == "complete")) {
|
|
$side = ColProperty::$COMPLETE;
|
|
}
|
|
}
|
|
$label = "";
|
|
$useColonAfterLabel = true;
|
|
if (count($parts) > 2) {
|
|
$label = $parts[2];
|
|
if (($label != "") && ($label[strlen($label)-1] == " ")) {
|
|
$useColonAfterLabel = false;
|
|
}
|
|
}
|
|
$varstyle = ColProperty::$NORMAL;
|
|
if (count($parts) > 3) {
|
|
switch(trim($parts[3])) {
|
|
case "hoch":
|
|
$varstyle = ColProperty::$HIGH;
|
|
break;
|
|
case "breit":
|
|
$varstyle = ColProperty::$WIDE;
|
|
break;
|
|
case "hochbreit":
|
|
$varstyle = ColProperty::$WIDEHIGH;
|
|
}
|
|
}
|
|
|
|
if (is_null(self::$tableProperties)) {
|
|
throw new Exception("TAB-Element fehlt in Vorlage");
|
|
}
|
|
$colSpec = self::$tableProperties->getColSpec(self::$curCol);
|
|
$colContent = $colSpec->render($realElem,$side,$label,$varstyle,$useColonAfterLabel);
|
|
return $colContent;
|
|
}
|
|
|
|
private static function substPlaceholder($vartext,$dataline) {
|
|
if ($vartext == '-') {
|
|
return null;
|
|
}
|
|
|
|
if (isset($dataline[$vartext])) {
|
|
return strval($dataline[$vartext]);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
private static function getParts($line) {
|
|
$matches = null;
|
|
preg_match_all('/\{[a-zA-Z0-9éöäüÖÄÜß_\'":\-=\+%\.,\/\(\) ]*\}/', $line, $matches);
|
|
return $matches[0];
|
|
}
|
|
|
|
private static function startsWith ($string, $startString)
|
|
{
|
|
$len = strlen($startString);
|
|
return (substr($string, 0, $len) === $startString);
|
|
}
|
|
|
|
private static function addToOut($t) {
|
|
if ($t == "\n") {
|
|
self::$outHtml .= "<br>";
|
|
self::$outPr[] = ColProperty::$LF;
|
|
} else {
|
|
self::$outHtml .= $t;
|
|
self::$outPr .= $t;
|
|
}
|
|
}
|
|
|
|
private static function setTableProperties($elem) {
|
|
self::$tableProperties = new TemplateTable($elem,self::$space);
|
|
self::$curCol = 0;
|
|
}
|
|
}
|
|
|