User:Woozle/strings.php

About
Defines the xtString extended-functionality string class, and a few other string utility functions.

Code
<?php /* PURPOSE: library for extended string classes HISTORY: 2009-10-23 Added constructor for xtString 2009-11-22 xtString.KeepOnly 2010-11-04   xtString.SplitFirst: added isList parameter Moved ParseTextLines here from SpecialVbzAdmin.php 2010-11-07 StrCat 2011-09-09 Tentatively commenting out libmgr.php requirement; it doesn't seem to be used

/* =================== CLASS: xtString PURPOSE: extended string functions if (defined( '__DIR__' )) { $fpThis = __DIR__; } else { $fpThis = dirname(__FILE__); }

/* if (!defined('LIBMGR')) { require('libmgr.php'); }

class xtString { public $Value; public $RepCount;	// replacement count public $DoKeep;	// TRUE = replace value with function results (scalar functions only)

public function __construct($iVal=NULL,$iKeep=TRUE) { $this->Value = $iVal; $this->DoKeep = $iKeep; }

// invoked when object is referenced as a string public function __toString { return $this->Value; }   /*      ACTION: Add $iAdd to the current string; if the current string is not empty, add $iSep first. */   public function AddSep($iAdd,$iSep=' ') { if (!empty($this->Value)) { $this->Value .= $iSep; }	$this->Value .= $iAdd; return $this->Value; }   /*      ACTION: Remove any characters in $iChars from the beginning of the string; stop when a non-$iChars character is found INPUT: $iChars = characters to delete; defaults to ltrim's default of trimming all whitespace */

public function DelLead($iChars=NULL) { if (is_null($iChars)) { $out = ltrim($this->Value); } else { $out = ltrim($this->Value,$iChars); }

if ($this->DoKeep) { $this->Value = $out; }

return $out; }   /*      ACTION: Remove any characters in $iChars from the end of the string; stop when a non-$iChars character is found */

public function DelTail($iChars=NULL) { if (is_null($iChars)) { $out = rtrim($this->Value); } else { $out = rtrim($this->Value,$iChars); }	if ($this->DoKeep) { $this->Value = $out; }

return $out; }

/*-     ACTION: Splits the string at the first match RETURNS: Array containing the part before in array['before'] and the part after in array['after'] ...or NULL if no match found. INPUT: iMatch = string to look for isList: TRUE = iMatch is a list of characters - finding any one of them is a match FALSE = iMatch is a string; the entire sequence must be found, in the same order */

public function SplitFirst($iMatch,$isList=FALSE) { $isFnd = FALSE; if ($isList) { $strFnd = strpbrk($this->Value,$iMatch); if ($strFnd === FALSE) { $out = NULL; } else { $idx = strpos($this->Value,$strFnd); $isFnd = TRUE; }	} else { $idx = strpos($this->Value,$iMatch); if ($idx === FALSE) { $out = NULL; } else { $isFnd = TRUE; }	}

if ($isFnd) { $out['index'] = $idx; $out['before'] = substr($this->Value,0,$idx); $out['after'] = substr($this->Value,$idx+1); }

return $out; }

public function SplitFinal($iMatch) { // NOT TESTED!

$idx = strrpos($this->Value,$iMatch); $out['index'] = $idx; $out['before'] = substr($this->Value,0,$idx-1); $out['after'] = substr($this->Value,$idx+1); return $out; }

/*     INPUT: $iList: array of targets and replacement values iList[target] = new value */   public function ReplaceList($iList) { $this->RepCount = 0; $intRep = 0; $out = $this->Value;

foreach($iList AS $seek => $repl) { $out = str_replace($seek,$repl,$out,$intRep); $this->RepCount += $intRep; }

if ($this->DoKeep) { $this->Value = $out; }

return $out; }

/*=====     ACTION: Replace any {{character sequences where all characters are found in $iChars} that are longer than $iMax} with the string $iRepl */   public function ReplaceSequence($iChars, $iRepl, $iMax=0) { $in = $this->Value; $out = ''; $lenIn = strlen($in); $rpos = 0;

while ($rpos < $lenIn) { $fnd = strspn($in,$iChars,$rpos); if ($fnd > 0) { // found a sequence; does it exceed $iMin? if ($fnd > $iMax) { // yes - replace it		   $out .= $iRepl; } else { // no - keep it		   $out .= substr($in,$rpos,$fnd); }		$rpos += $fnd;	// advance the read pointer } else { // matching sequence not found at current position, so gobble up non-matching chars until the next one $fnd = strcspn($in,$iChars,$rpos); $add = substr($in,$rpos,$fnd); $out .= $add; $rpos += $fnd;	// advance the read pointer }	}	if ($this->DoKeep) { $this->Value = $out; }

return $out; }

/*     ACTION: Keep only characters matching the given regex pattern EXAMPLE: KeepOnly('0-9') would remove all non-numeric characters */   public function KeepOnly($iPattern) { $out = preg_replace('/[^'.$iPattern.']/','',$this->Value); if ($this->DoKeep) { $this->Value = $out; }	return $out; }

/*     ACTION: delete all characters outside of the given range */   public function DelAscRange($iLow, $iHi) { /* VB var defs Dim strIn As String Dim strOut As String Dim strIdx As Long Dim chIn As Byte Dim cntDel As Long $strIn = $this->Value; $strOut = ''; $intLen = strlen($strIn); for ($strIdx = 0; $strIdx < $intLen; $strIdx++) { $chIn = substr($strIn, $strIdx, 1); $chInAsc = ord($chIn); If (($chInAsc < $iLow) || ($chInAsc > $iHi)) { $strOut .= $chIn; }	}

$cntDel = strlen($this->Value) - strlen($strOut); if ($this->DoKeep) { $this->Value = $strOut; }

return $cntDel; }

public function Xplode { $tok = substr ( $this->Value, 0, 1);	// token for splitting if ($tok) { $tks = substr ( $this->Value, 1 );	// tokenized string $list = explode ( $tok, $tks );	// split the string return $list; } else { return NULL; }   }

/*     ACTION: Parses a block of text lines into an array, where the key for each element is the text up to the first space and the value is the rest of the line. INPUT: (arg) iOpts: array of possible options [comment] = list of characters which begin a comment. When one of these characters is found, the rest of the line is ignored. Defaults to "!;" [blanks] = list of characters considered to be "blanks". Runs of one or more of these are consolidated to a single space before parsing. Spaces then are considered separators between pieces of the line. Defaults to space + tab [sep] = string to use for column separator (must not appear within a column) Defaults to space. [line]: format in which each line is returned 'str': line contents are returned as a single string (default), first column is index 'arr': line contents are returned as an array; lines are indexed numerically 'arrx': same as arr, but line is Xploded instead of using a specified separator OUTPUT: array containing one line of text per element HISTORY: 2010-11-27 Added line=arrx option. 2011-02-06 Doesn't seem to handle arrx where the separator is TAB - TABs get stripped from start of line. Made a small code change to fix this, but it didn't change the output. Fix later. */   public function ParseTextLines(array $iOpts=NULL) { $chsComment = nz($iOpts['comment'],'!;'); $chsBlanks = nz($iOpts['blanks']," \t"); $strSep = nz($iOpts['sep'],' '); $doArrX = (nz($iOpts['line']) == 'arrx'); $doArr = $doArrX || (nz($iOpts['line']) == 'arr');

$arLines = preg_split("/\n/",$this->Value); if (is_array($arLines)) { $xts = new xtString; $arOut = NULL; foreach ($arLines as $idx => $line) { $xts->Value = $line; $arSplit = $xts->SplitFirst($chsComment,TRUE);		// split at first comment character if (is_null($arSplit)) { // no comment found; use entire line } else { // use only portion of line before comment $xts->Value = $arSplit['before']; } //		$xts->DelLead($chsBlanks);				// remove any leading spaces if (!empty($chsBlanks)) { $xts->Value = trim($xts->Value,$chsBlanks."\r");	// remove any leading or trailing blanks/CR $xts->ReplaceSequence($chsBlanks,$strSep);		// replace all blank sequences with separator string }

if ($xts->Value != '') {	// if there's anything left... if ($doArr) { // split it into columns and add that to the output array if ($doArrX) { $arSplit = $xts->Xplode; } else { $arSplit = explode($strSep,$xts->Value); }

$arOut[] = $arSplit; } else { // split it into key/value pair and add to output array $arSplit = $xts->SplitFirst($strSep);		// split at first separator $strKey = $arSplit['before']; $strVal = $arSplit['after']; $arOut[$strKey] = $strVal; }		}	   }	    return $arOut; } else { return NULL; }   } }

/* ORIGINAL VERSION class Cipher { private $securekey, $iv; function __construct($textkey) { $this->securekey = hash('sha256',$textkey,TRUE); $this->iv = mcrypt_create_iv(32); }   function encrypt($input) { return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->securekey, $input, MCRYPT_MODE_ECB, $this->iv)); }   function decrypt($input) { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->securekey, base64_decode($input), MCRYPT_MODE_ECB, $this->iv)); } }

class Cipher { private $securekey, $iv;

function __construct($iKey) { $this->securekey = hash('sha256',$iKey,TRUE); }

public function Seed($iValue=NULL) { if (!is_null($iValue)) { $this->iv = $iValue; }

return $this->iv; }

public function MakeSeed { $this->iv = mcrypt_create_iv(32); return $this->iv; }

public function encrypt($input) { if (!isset($this->iv)) { $this->MakeSeed; }

return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->securekey, $input, MCRYPT_MODE_ECB, $this->iv)); }

public function decrypt($input) { if (empty($this->iv)) { return 'ENCRYPTION SEED NOT SET!'; } else { return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->securekey, base64_decode($input), MCRYPT_MODE_ECB, $this->iv)); }   } }

class xtTime {

public function __construct($iValue=NULL) { if (is_string($iValue)) { $this->Parse($iValue); }   }

public function Parts($iYear=NULL,$iMonth=NULL,$iDay=NULL,$iHour=NULL,$iMin=NULL,$iSec=NULL) { if (!is_null($iYear))	{ $this->intYr = $iYear; } if (!is_null($iMonth))	{ $this->intMo = $iMonth; } if (!is_null($iDay))	{ $this->intDy = $iDay; } if (!is_null($iHour))	{ $this->intHr = $iHour; } if (!is_null($iMin))	{ $this->intMi = $iMin; } if (!is_null($iSec))	{ $this->intSe = $iSec; } }

public function PartsArray($iArray=NULL) { if (!is_null($iArray)) { $intYr = nz($iArray['year']); $intMo = nz($iArray['month']); $intDy = nz($iArray['day']); $intHr = nz($iArray['hour']); $intMi = nz($iArray['minute']); $intSe = nz($iArray['second']); $this->Parts($intYr,$intMo,$intDy,$intHr,$intMi,$intSe); }

$arOut = array(	 'year'	=> nz($this->intYr),	  'month'	=> nz($this->intMo),	  'day'		=> nz($this->intDy),	  'hour'	=> nz($this->intHr),	  'minute'	=> nz($this->intMi),	  'second'	=> nz($this->intSe));

return $arOut; }

public function Year($iYear=NULL) { if (!is_null($iYear)) { $this->intYr = $iYear; }	return $this->intYr; }

public function Parse($iString) {		// date and/or time $this->DateParse($iString); }

public function DateParse($iString) { $arDate = date_parse($iString); $this->PartsArray($arDate); }

public function HasTime { return !empty($this->intHr); }

public function FormatSortable($iSep='-') { $out = $this->intYr.$iSep.sprintf('%02u',$this->intMo).$iSep.sprintf('%02u',$this->intDy); return $out; }

public function FormatSQL { $out = $this->intYr.'/'.$this->intMo.'/'.$this->intDy; if ($this->HasTime) { $out .= ' '.$this->intHr.':'.$this->intMi.':'.$this->intSe; }	return $out; }

/*   public function DateTimeObj { $dtOut = new DateTime($this->Format('Y-);   }

public function AssumeYear($iMonthsAhead) { if (empty($this->intYr)) { $intYrCur = date('Y'); $this->intYr = $intYrCur; if (isset($this->intMo)) { $intMoCur = date('n'); if (($this->intMo - $intMoCur) > $iMonthsAhead) { $this->intYr--; }	   }	}    } }

/* function nz(&$iVar,$iDefault=NULL) { if (isset($iVar)) { if (!is_null($iVar)) { return $iVar; }   }    return $iDefault; }

// these variants may be unnecessary

function nzInt(&$iVar,$iDefault=0) { if (isset($iVar)) { if (!is_null($iVar)) { return $iVar; }   }    return $iDefault; }

function nzStr(&$iVar,$iDefault='') { if (isset($iVar)) { if (!is_null($iVar)) { return $iVar; }   }    return $iDefault; }

/* ACTION: Concatenates two strings. If both are non-empty, separate them with iSep. function StrCat($iLeft,$iRight,$iSep) { if (empty($iLeft) || empty($iRight)) { return $iLeft.$iRight; } else { return $iLeft.$iSep.$iRight; } } /* ACTION: Parses a block of text lines into an array, where the key for each element is the text up to the first space and the value is the rest of the line. DEPRECATED; use xtString::ParseTextLines

function ParseTextLines($iText,$iComment='!;',$iBlanks=" \t") { $arLines = preg_split("/\n/",$iText); if (is_array($arLines)) { $xts = new xtString; $arOut = NULL; //$doDeptOnly = $this->AffectsCatNum; foreach ($arLines as $idx => $line) { $xts->Value = $line; $arSplit = $xts->SplitFirst($iComment,TRUE);	// split at first comment character $xts->Value = $arSplit['before']; $xts->ReplaceSequence($iBlanks, ' ');		// replace all blanks with single space $xts->DelLead(' ');					// remove any leading spaces if ($xts->Value != '') { // if there's anything left, split it into key/value pair and add to output array $arSplit = $xts->SplitFirst(' ');			// split at first space $strKey = $arSplit['before']; $sqlFilt = ''; $strVal = $arSplit['after']; $arOut[$strKey] = $strVal; }	}	return $arOut; } else { return NULL; } }