<?php
// {{{ Header
/*
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| SIERRA : PHP Application Framework http://code.google.com/p/sierra-php |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Copyright 2005 Jason Read |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.|
| See the License for the specific language governing permissions and |
| limitations under the License. |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
*/
// }}}
// {{{ Constants
/**
* regular expression used to locate an ip address
* @type string
*/
define('SRA_UTIL_IP_REGEX', '/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/');
/**
* the name of the aspell cli utility used by the getSpellCheckLanguages and
* spellcheck methods. aspell must be installed and present in the $PATH in
* order to use those methods
* @type string
*/
define('SRA_UTIL_ASPELL', 'aspell');
/**
* unit identifiers for a 'bit', this is the smallest unit size. the
* SRA_UTIL_DATA_UNIT_* constants are used by the SRA_Util::normalizeDataUnit
* method below
* @type string
*/
define('SRA_UTIL_DATA_UNIT_BIT', 'b');
/**
* unit identifiers for a 'byte'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_BYTE', 'B');
/**
* unit identifiers for a 'kilobit'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_KILOBIT', 'Kb');
/**
* unit identifiers for a 'kilobyte'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_KILOBYTE', 'KB');
/**
* unit identifiers for a 'megabit'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_MEGABIT', 'Mb');
/**
* unit identifiers for a 'megabyte'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_MEGABYTE', 'MB');
/**
* unit identifiers for a 'gigabit'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_GIGABIT', 'Gb');
/**
* unit identifiers for a 'gigabyte'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_GIGABYTE', 'GB');
/**
* unit identifiers for a 'terabit'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_TERABIT', 'Tb');
/**
* unit identifiers for a 'terabyte'
* @type string
*/
define('SRA_UTIL_DATA_UNIT_TERABYTE', 'TB');
/**
* space separated list of unit labels used to identify a bit. if a label is
* prefixed with : the search for it will not be case sensitive
* @type string
*/
define('SRA_UTIL_DATA_UNIT_BIT_LABELS', 'b,b/s,:bit,:bit/s,,bs,,bS,,bps,bpS,,,b/S,,,,,,,:bits,:bits/s,');
/**
* space separated list of unit labels used to identify a byte
* @type string
*/
define('SRA_UTIL_DATA_UNIT_BYTE_LABELS', 'B,B/s,:byte,:byte/s,,Bs,,BS,,Bps,BpS,,,B/S,,,,,,,:bytes,:bytes/s,');
/**
* space separated list of unit labels used to identify a kilobit
* @type string
*/
define('SRA_UTIL_DATA_UNIT_KILOBIT_LABELS', 'Kb,Kb/s,:kilobit,:kilobit/s,kb,Kbs,kbs,KbS,kbS,Kbps,KbpS,kbps,kbpS,Kb/S,kb/s,kb/S,:kbit,:kbits,:kbit/s,:kilo bit,:kilobits,:kilobits/s,:kilo bits');
/**
* space separated list of unit labels used to identify a kilobyte
* @type string
*/
define('SRA_UTIL_DATA_UNIT_KILOBYTE_LABELS', 'KB,KB/s,:kilobyte,:kilobyte/s,kB,KBs,kBs,KBS,kBS,KBps,KBpS,kBps,kBpS,KB/S,kB/s,kB/S,:kbyte,:kbytes,:kbyte/s,:kilo byte,:kilobytes,:kilobytes/s,:kilo bytes');
/**
* space separated list of unit labels used to identify a megabit
* @type string
*/
define('SRA_UTIL_DATA_UNIT_MEGABIT_LABELS', 'Mb,Mb/s,:megabit,:megabit/s,mb,Mbs,mbs,MbS,mbS,Mbps,MbpS,mbps,mbpS,Mb/S,mb/s,mb/S,:mbit,:mbits,:mbit/s,:mega bit,:megabits,:megabits/s,:mega bits');
/**
* space separated list of unit labels used to identify a megabyte
* @type string
*/
define('SRA_UTIL_DATA_UNIT_MEGABYTE_LABELS', 'MB,MB/s,megabyte,megabyte/s,mB,MBs,mBs,MBS,mBS,MBps,MBpS,mBps,mBpS,MB/S,mB/s,mB/S,:mbyte,:mbytes,:mbyte/s,:mega byte,megabytes,megabytes/s,:mega bytes');
/**
* space separated list of unit labels used to identify a gigabit
* @type string
*/
define('SRA_UTIL_DATA_UNIT_GIGABIT_LABELS', 'Gb,Gb/s,:gigabit,:gigabit/s,gb,Gbs,gbs,GbS,gbS,Gbps,GbpS,gbps,gbpS,Gb/S,gb/s,gb/S,:gbit,:gbits,:gbit/s,:giga bit,:gigabits,:gigabits/s,:giga bits');
/**
* space separated list of unit labels used to identify a gigabyte
* @type string
*/
define('SRA_UTIL_DATA_UNIT_GIGABYTE_LABELS', 'GB,GB/s,:gigabyte,:gigabyte/s,gB,GBs,gBs,GBS,gBS,GBps,GBpS,gBps,gBpS,GB/S,gB/s,gB/S,:gbyte,:gbytes,:gbyte/s,:giga byte,:gigabytes,:gigabytes/s,:giga bytes');
/**
* space separated list of unit labels used to identify a terabit
* @type string
*/
define('SRA_UTIL_DATA_UNIT_TERABIT_LABELS', 'Tb,Tb/s,:terabit,:terabit/s,tb,Tbs,tbs,TbS,tbS,Tbps,TbpS,tbps,tbpS,Tb/S,tb/s,tb/S,:tbit,:tbits,:tbit/s,:tera bit,:terabits,:terabits/s,:tera bits');
/**
* space separated list of unit labels used to identify a terabyte
* @type string
*/
define('SRA_UTIL_DATA_UNIT_TERABYTE_LABELS', 'TB,TB/s,:terabyte,:terabyte/s,tB,TBs,tBs,TBS,tBS,TBps,TBpS,tBps,tBpS,TB/S,tB/s,tB/S,:tbyte,:tbytes,:tbyte/s,:tera byte,:terabytes,:terabytes/s,:tera bytes');
/**
* measurement identifiers for a 'centimeter'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_CENTIMETER', 'cm');
/**
* measurement identifiers for a 'foot'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_FOOT', 'ft');
/**
* measurement identifiers for an 'inch'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_INCH', 'in');
/**
* measurement identifiers for a 'kilometer'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_KILOMETER', 'km');
/**
* measurement identifiers for a 'meter'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_METER', 'm');
/**
* measurement identifiers for a 'mile'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_MILE', 'mi');
/**
* measurement identifiers for a 'yard'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_YARD', 'yd');
/**
* measurement identifiers for a 'gram'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_GRAM', 'gm');
/**
* measurement identifiers for a 'kilogram'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_KILOGRAM', 'kg');
/**
* measurement identifiers for an 'ounce'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_OUNCE', 'oz');
/**
* measurement identifiers for a 'pound'
* @type string
*/
define('SRA_UTIL_MEASUREMENT_POUND', 'lb');
/**
* the root username
* @type string
*/
define('SRA_UTIL_ROOT', 'root');
/**
* path to the services config file used by SRA_Util::getServiceName($port)
* @type string
*/
define('SRA_UTIL_SERVICES_CONFIG', '/etc/services');
/**
* string token that identifies an invalid password in SRA_Util::suCmds
* @type string
*/
define('SRA_UTIL_SU_CMDS_INVALID_PSWD', 'incorrect password|: Authentication failure');
/**
* string token that identifies an invalid user in SRA_Util::suCmds
* @type string
*/
define('SRA_UTIL_SU_CMDS_INVALID_USER', 'not exist|Unknown id:');
/**
* the name of the temporary script created by SRA_Util::suCmds
* @type string
*/
define('SRA_UTIL_SU_CMDS_SCRIPT', '.su-cmds');
/**
* string token that identifies the password prompt in SRA_Util::suCmds and
* SRA_Util::suPswd
* @type string
*/
define('SRA_UTIL_SU_PASSWORD', '"assword:"');
/**
* string token that identifies an bad password in SRA_Util::suPswd
* @type string
*/
define('SRA_UTIL_SU_PSWD_BAD', 'BAD');
/**
* string token that identifies the retype password command in SRA_Util::suPswd
* @type string
*/
define('SRA_UTIL_SU_PSWD_RETYPE', 'etype');
/**
* The value to use in the printDebug method to identify that the app debug flag should be used
* @type int
*/
define('SRA_UTIL_USE_APP_CONFIG_DEBUG', -1);
/**
* The value to use in the printDebug method to identify that the system debug flag should be used
* @type int
*/
define('SRA_UTIL_USE_SYS_CONFIG_DEBUG', -2);
/**
* regular expression used to strip out non-url-safe characters
* @type string
*/
define('SRA_UTIL_URL_SAFE_REGEX', '|[^\w-_\.]|');
// }}}
// {{{ Includes
// }}}
// {{{ SRA_Util
/**
* This class is used to house random methods that do not logically belong in any other classes.
* Generally these methods will be used for minor calculations and processes that may be useful
* to other classes. All of the methods in this class are static.
*
* @author: Jason Read <hide@address.com>
* @package sierra.util
*/
class SRA_Util {
// {{{ Properties
// }}}
// {{{ addDelimString()
/**
* This method is used add or imbed a delimeter string. For example, if parsing a csv file you
* would want to use this method to convert commas in between quotes to a delim string that
* could later be converted back to a comma. This method would perform that function.
*
* @param string - The String to add the delimeter string to
* @param delim - The delimeter to imbed a delimeter string for (by default a comma).
* @param quote - The quote for the string (only delims between this will be replaced).
* The default is a double quote.
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function addDelimString( $string, $delim=",", $quote='"' )
{
$temp=explode($quote, $string);
for ($i=1; $i<count($temp); $i+=2)
$temp[$i]=str_replace($delim, "<delim>", $temp[$i]);
return implode($quote, $temp);
}
// }}}
// {{{ addSqlOption()
/**
* This static method adds an option to a sql statement. It uses the WHERE clause if no options
* exist in the sql statement. Otherwise it uses the AND clause.
*
* @param sql - The sql statement to add the option to.
* @param option - The option to add to the sql statement.
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function addSqlOption( $sql, $option )
{
if (strpos($sql, "WHERE"))
$sql.=" AND " . $option;
else
$sql.=" WHERE " . $option;
return $sql;
}
// }}}
// {{{ applyLimitOffset
/**
* used to apply limit and offset contraints to an array. returns a new
* array with those constraints applied
* @param array $arr the array to apply the limit/offset to
* @param int $limit the limit (if none, no limit will be applied)
* @param int $offset the offset (if none, no offset will be applied)
* @param boolean $preserveKeys whether or not to preserve the keys in $arr
* @access public static
* @return array
*/
function &applyLimitOffset(& $arr, $limit, $offset, $preserveKeys=FALSE) {
$newArray = array();
$keys = array_keys($arr);
$offsetCounter = 0;
$counter = 0;
foreach($keys as $key) {
if (!$offset || ($offset && $offsetCounter >= $offset)) {
$counter++;
$preserveKeys ? $newArray[$key] =& $arr[$key] : $newArray[] =& $arr[$key];
if ($limit && $counter == $limit) { break; }
}
$offsetCounter++;
}
return $newArray;
}
// }}}
// {{{ arrayMerge()
/**
* This method merges two arrays based on the parameters specified.
*
* @param master : String[] - The master array to merge from. This will be a key based array.
* @param merge : String[] - The merge array. This will also be a key based array. At the end of the method
* all of the key based values in the master array will exist in this array.
* @param overwriteExisting : boolean - Optional parameter that specifies whether or not existing values should
* be overwritten if then exist already in the merge array. The default value for this is true.
* @access public static
* @return String[]
* @author Jason Read <hide@address.com>
*/
function &arrayMerge( & $master, $merge, $overwriteExisting=true )
{
$keys = array_keys($master);
foreach ($keys as $key)
{
if (is_array($master[$key]))
{
if (!array_key_exists($key, $merge) || !is_array($merge[$key]))
{
$merge[$key] = array();
}
$merge[$key] =& SRA_Util::arrayMerge($master[$key], $merge[$key], $overwriteExisting);
}
else if (is_array($merge) && (!array_key_exists($key, $merge) || $overwriteExisting))
{
$merge[$key] = $master[$key];
}
}
return $merge;
}
// }}}
// {{{ arrayToCsv()
/**
* This method converts an array of arrays of strings to a csv formatted string. Each row in
* the array will be separated by a line break "\n" and each column will be separated by a
* comma and surrounded by double quotes (if the useQuotes parameter is true).
*
* @param report : String[][] - An array of string arrays. Each array in the first array will
* be considered a row and each element in the second arrays will be considered a column.
* @param useQuotes : boolean - Whether or not each column should be double quote delimited.
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function &arrayToCsv( & $report, $useQuotes = true )
{
// Validate table
if (!is_array($report))
{
$msg = "SRA_Util::arrayToCsv: Failed - report parameter is not an array: '" . gettype($report) . "'";
return SRA_Error::logError($msg, __FILE__, __LINE__, SRA_ERROR_PROBLEM, SAP_APPLICATION_DEBUG);
}
$keys = array_keys($report);
$buffer = "";
$firstRow = true;
foreach ($keys as $key)
{
// Validate row
if (!is_array($report[$key]))
{
$msg = "SRA_Util::arrayToCsv: Failed - report row is not an array: '" . gettype($report[$key]) . "'";
return SRA_Error::logError($msg, __FILE__, __LINE__, SRA_ERROR_PROBLEM, SAP_APPLICATION_DEBUG);
}
$tkeys = array_keys($report[$key]);
$start = true;
foreach ($tkeys as $tkey)
{
if ($start)
{
if (!$firstRow)
{
$buffer .= "\r\n";
}
else
{
$firstRow = false;
}
$start = false;
}
else
{
$buffer .= ",";
}
if ($useQuotes && strstr($report[$key][$tkey], ","))
{
$buffer .= "\"";
$buffer .= str_replace("\"", "'", $report[$key][$tkey]);
}
else
{
$buffer .= $report[$key][$tkey];
}
if ($useQuotes && strstr($report[$key][$tkey], ","))
{
$buffer .= "\"";
}
}
}
return $buffer;
}
// }}}
// {{{ toJson
/**
* converts $attr to the appropriate representation in a javascript evaluable
* string. the global variables $_utilDateFormat and $_utilTimeFormat
* may be specified to use an alternate date/time format
* @param mixed $attr the attribute to render
* @param array $include if $attr is an entity, the attributes to render
* @param array $exclude if $attr is an entity, the attributes not to render
* @param boolean $javascriptDate whether or not is $attr is a
* SRA_GregorianDate object, it should be converted to a javascript Date
* object
* @access public
* @return String
*/
function toJson(& $attr, $include, $exclude, $javascriptDate=FALSE) {
global $_utilDateFormat;
global $_utilTimeFormat;
$js = '';
if (is_array($attr)) {
$numeric = SRA_Util::isNumericArray($attr);
$js .= $numeric ? '[' : '{';
$keys = array_keys($attr);
foreach($keys as $key) {
$js .= $keys[0] == $key ? '' : ', ';
$js .= $numeric ? '' : '"' . str_replace('"', '\"', $key) . '": ';
$js .= SRA_Util::toJson($attr[$key], $include, $exclude, $javascriptDate);
}
$js .= $numeric ? ']' : '}';
}
else {
if (is_numeric($attr) || preg_match('/new Date\((.*)\)/', $attr)) {
$js .= $attr;
}
else if (is_bool($attr)) {
$js .= $attr ? 'true' : 'false';
}
else if (class_exists('SRA_GregorianDate') && SRA_GregorianDate::isValid($attr) && $javascriptDate) {
$js .= 'new Date(' . $attr->getYear() . ', ' . ($attr->getMonth() - 1) . ', ' . $attr->getDay() . (!$attr->isDateOnly() ? ', ' . $attr->getHour() . ', ' . $attr->getMinute() . ', ' . $attr->getSecond() : '') . ')';
}
else if (class_exists('SRA_GregorianDate') && SRA_GregorianDate::isValid($attr)) {
$js .= '"' . ($attr->isDateOnly() && $_utilDateFormat ? $attr->format($_utilDateFormat) : (!$attr->isDateOnly() && $_utilTimeFormat ? $attr->format($_utilTimeFormat) : $attr->toString())) . '"';
}
else if (class_exists('SRA_FileAttribute') && SRA_FileAttribute::isValid($attr)) {
$xmlArray = $attr->toXmlArray();
$js .= SRA_Util::toJson($xmlArray['attributes']);
}
else if (is_object($attr) && method_exists($attr, 'toJson')) {
$js .= $attr->toJson($include, $exclude, NULL, $javascriptDate);
}
else if ($attr) {
$js .= '"' . str_replace("\r", '\n', str_replace("\n", '\n', str_replace('"', '\"', str_replace('\\', '\\\\', $attr)))) . '"';
}
else {
$js .= 'null';
}
}
return $js;
}
// }}}
// {{{ attrToXml
/**
* converts $attr to the appropriate representation in a xml renderable array.
* the global variables $_utilDateFormat and $_utilTimeFormat may be
* specified to use an alternate date/time format
* @param mixed $attr the attribute to render
* @param array $include if $attr is an entity, the attributes to render
* @param array $exclude if $attr is an entity, the attributes not to render
* @param string $fileElementName the element name to use for file attributes
* @param boolean $usePrimaryKey whether or not to use primary key to
* serialize entities (otherwise the 'toXmlArray' method will be used)
* @param boolean $camelCase whether or not to force the xml attributes and
* elements to camel case (otherwise, model defined format will be used)
* @param string $ikey optional parameter used internally for recursive calls
* @access public
* @return string
*/
function attrToXml(& $attr, $include, $exclude, $fileElementName=NULL, $usePrimaryKey=FALSE, $camelCase=FALSE, $ikey=NULL) {
global $_utilAttrToXmlSoap;
global $_utilDateFormat;
global $_utilTimeFormat;
$xml = NULL;
if (is_array($attr)) {
$xml = '<array' . ($ikey ? ' key="' . htmlspecialchars($ikey) . '"' : '') . ">\n";
$isHash = SRA_Util::isHash($attr);
foreach(array_keys($attr) as $key) {
if ((is_object($attr[$key]) && method_exists($attr, 'toXmlArray')) || is_array($attr[$key])) {
$val = SRA_Util::attrToXml($attr[$key], $include, $exclude, $fileElementName, $usePrimaryKey, $camelCase, $isHash ? $key : NULL);
$xml .= $val . "\n";
}
}
foreach(array_keys($attr) as $key) {
if ((!is_object($attr[$key]) || !method_exists($attr, 'toXmlArray')) && !is_array($attr[$key])) {
$val = SRA_Util::attrToXml($attr[$key], $include, $exclude, $fileElementName, $usePrimaryKey, $camelCase);
$tval = trim($val);
if (!SRA_Util::beginsWith($tval, '<') || !SRA_Util::endsWith($tval, '>') || SRA_Util::beginsWith($tval, '<![CDATA[')) {
$val = '<' . ($camelCase ? 'arrayItem' : 'array-item') . ($isHash ? ' key="' . htmlspecialchars($key) . '"' : '') . '>' . $val . '</' . ($camelCase ? 'arrayItem' : 'array-item') . ">\n";
}
$xml .= $val;
}
}
$xml .= "</array>\n";
}
else {
if (is_numeric($attr)) {
$xml = $attr;
}
else if (is_bool($attr)) {
$xml = $attr ? '1' : '0';
}
else if (SRA_GregorianDate::isValid($attr)) {
$xml = $_utilAttrToXmlSoap ? $attr->format('c') : ($attr->isDateOnly() && $_utilDateFormat ? $attr->format($_utilDateFormat) : (!$attr->isDateOnly() && $_utilTimeFormat ? $attr->format($_utilTimeFormat) : $attr->toString()));
}
else if (SRA_FileAttribute::isValid($attr)) {
$xml = SRA_XmlParser::arrayToXML($attr->toXmlArray($fileElementName));
}
else if (is_object($attr) && method_exists($attr, 'toXmlArray')) {
$xml = $usePrimaryKey && method_exists($attr, 'getPrimaryKey') && $attr->entityHasPersistence() ? $attr->getPrimaryKey() : SRA_XmlParser::arrayToXML($attr->toXmlArray($include, $exclude, $usePrimaryKey, $camelCase));
}
else if ($attr) {
$xml = '<![CDATA[' . $attr . ']]>';
}
}
return $xml;
}
// }}}
// {{{ isHash
/**
* returns TRUE if $arr is a hash (array indexes do not start with 0 and
* increment)
* @param array $arr the array to check
* @access public
* @return boolean
*/
function isHash(&$arr) {
if (is_array($arr)) {
$idx = 0;
foreach(array_keys($arr) as $key) {
if ($idx++ !== $key) { return TRUE; }
}
}
return FALSE;
}
// }}}
// {{{ beginsWith
/**
* returns TRUE if the $str specified begins with $substr
* @param string $str the string to chec
* @param string $substr the string to check for
* @param boolean $caseSensitive whether or not case sensitive
* @access public
* @return boolean
*/
function beginsWith($str, $substr, $caseSensitive = TRUE) {
if (!$caseSensitive) {
$str = strtolower($str);
$substr = strtolower($substr);
}
return (substr($str, 0, strlen($substr)) == $substr);
}
// }}}
// {{{ endsWith
/**
* returns TRUE if the $str specified ends with $substr
* @param string $str the string to chec
* @param string $substr the string to check for
* @param boolean $caseSensitive whether or not case sensitive
* @access public
* @return boolean
*/
function endsWith($str, $substr, $caseSensitive = TRUE) {
if (!$caseSensitive) {
$str = strtolower($str);
$substr = strtolower($substr);
}
return (substr($str,-strlen($substr)) == $substr);
}
// }}}
// {{{ arrayMoveToTop
/**
* moves the array element $key to the top of the array and returns the new
* array
* @param array $arr the array
* @param string $key the hash key of the element to move
* @access public
* @return array
*/
function &arrayMoveToTop(&$arr, $key) {
if (is_array($arr) && $key && isset($arr[$key])) {
$narr = array($key => $arr[$key]);
foreach(array_keys($arr) as $i) {
if ($i != $key) {
$narr[$i] = $arr[$i];
}
}
return $narr;
}
else {
return $arr;
}
}
// }}}
// {{{ bufferArray()
/**
* This method is used to convert an array into text (which may be imported into php at some
* point in the future to become an array). This method supports any number of levels of arrays.
*
* @param array. Array. The array to buffer.
* @param name. String. The name to give the array.
* @param tabs. int. The number of spaces to indent each successive level.
* @param recursive. boolean. Whether or not this is a recursive call.
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function bufferArray( & $array, $name, $indent=2, $recursive = false )
{
if (!$recursive)
{
$buffer = '$' . $name . " = array(";
}
else
{
$buffer = "array(";
}
foreach ($array as $key => $value)
{
if (isset($addComma))
{
$buffer .= ",\n";
for ($i=0; $i<=$indent; $i++)
{
$buffer .= " ";
}
}
if (!is_int($key))
{
$key = "'" . str_replace("'", "\\'", $key) . "'";
}
if (is_array($value))
{
$buffer .= $key . " => \n";
for ($i=0; $i<=$indent; $i++)
{
$buffer .= " ";
}
$buffer .= SRA_Util::bufferArray($value, $name, $indent * 2, true);
}
else
{
if (!is_int($value))
{
$value = str_replace("'", "\\'", $value);
$value = "'" . str_replace("\\\\'", "\\'", $value) . "'";
}
$buffer .= $key . " => " . $value;
}
$addComma=true;
}
$buffer .= ")";
if (!$recursive)
{
$buffer .= ";";
}
return($buffer);
}
// }}}
// {{{ camelCaseToDashes
/**
* returns the camel case variable name in a dash format
* e.g. myVariableName would return my-variable-name
* @param string $str the string to convert
* @param boolean $upper whether or not the new value should be all uppercase
* default is all lowercase
* @access public
* @return String
*/
function camelCaseToDashes($str, $upper = FALSE) {
return SRA_Util::camelCaseConvert($str, '-', $upper);
}
// }}}
// {{{ camelCaseToUnderscores
/**
* returns the camel case variable name in an underscore format
* e.g. myVariableName would return my_variable_name
* @param string $str the string to convert
* @param boolean $upper whether or not the new value should be all uppercase
* default is all lowercase
* @access public
* @return String
*/
function camelCaseToUnderscores($str, $upper = FALSE) {
return SRA_Util::camelCaseConvert($str, '_', $upper);
}
// }}}
// {{{ camelCaseConvert
/**
* converts a camel case (ie 'myNameIsBob') value into a fixed case value using
* $delim as the value to place between each camel case occurrence. for
* example, if $delim was '_' the value above would become 'my_name_is_bob'
* @param string $str the string to convert
* @param string $delim the delimeter to insert between each camel case occurrence
* @param boolean $upper whether or not the new value should be all uppercase
* default is all lowercase
* @access public
* @return String
*/
function camelCaseConvert($str, $delim, $upper = FALSE) {
$newStr = '';
for($i=0; $i<strlen($str); $i++) {
$char = substr($str, $i, 1);
if ($char != $delim && !$lastCap && strtoupper($char) == $char && $i > 0 && !is_numeric($char)) {
$newStr .= $delim;
}
$lastCap = strtoupper($char) == $char && !is_numeric($char);
$newStr .= $char;
}
if ($upper) {
$newStr = strtoupper($newStr);
}
else {
$newStr = strtolower($newStr);
}
return $newStr;
}
// }}}
// {{{ checkBrowserCompatibility
/**
* checks for browser compatibility and displays an error page when an
* incompatible browser is encountered. when the php script is being run at
* the command line, the compatibility check will be bypassed
* @param mixed $browsers either a text file containing line separated list of
* supported browsers or an array of supported browsers. for example:
* array('Firefox', 'Safari')
* @param string $errorTpl the template to display when an incompatible
* browser is encountered
* @access public
* @return void
*/
function checkBrowserCompatibility($supportedBrowsers, $errorTpl) {
if (!is_array($supportedBrowsers) && file_exists($supportedBrowsers)) {
$supportedBrowsers = file($supportedBrowsers);
}
if (!isset($_SERVER['argv'][0]) && is_array($supportedBrowsers) && count($supportedBrowsers)) {
$found = FALSE;
foreach($supportedBrowsers as $supportedBrowser) {
if (!SRA_Util::beginsWith($supportedBrowser, '#') && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), strtolower(trim($supportedBrowser))) !== FALSE) {
$found = TRUE;
break;
}
}
if (!$found) {
$tpl =& SRA_Controller::getAppTemplate();
$tpl->display($errorTpl);
exit;
}
}
}
// }}}
// {{{ codeToString()
/**
* This method converts a php code string into the resultant string (results of executing the
* php code). This function must also reside outside of the SRA_Util class in order for the regular
* expression call back function to work.
*
* @param $code. String. The php code to execute. This should only contain 1 line of code with
* or without the trailing ;
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function codeToString( $code )
{
$code = is_array($code) ? $code[1] : $code;
// Check if is valid
if (!is_string($code)) {
return(SRA_Error::logError("SRA_Util::codeToString: Failed - Invalid code: '$code'",
__FILE__, __LINE__, SRA_ERROR_PROBLEM));
}
// Add semi-colon
$code = trim($code);
if (substr($code, strlen($code) - 1 , 1) != ";") {
$code .= ";\n";
}
$code = '$value = ' . $code;
eval($code);
return isset($value) ? $value : SRA_Error::logError("SRA_Util::codeToString: Failed - Invalid code: '$code'", __FILE__, __LINE__, SRA_ERROR_PROBLEM);
}
// }}}
// {{{ compareBitMasks()
/**
* This method compares two bitmasks. It returns true if all of the bits specified in the mask
* parameter are also specified in the compare parameter.
*
* @param $mask. int. The bit mask containing the bits that need to be verified.
* @param $compare. int. The bits to validate.
* @param $full. int. Bitmask containing all of the possible bits for the mask parameter set.
* @access public static
* @return boolean
* @author Jason Read <hide@address.com>
*/
function compareBitMasks( $mask, $compare, $full )
{
for ($i=1; $i<$full; $i*=2)
{
echo "checking $i \n";
// Bit occurs in compare mask
if ($i & $compare)
{
echo "$i occurs in compare mask\n";
if (!($i & $mask))
{
echo "$i does not occur in mask, failed\n";
return false;
}
else
{
echo "$i occurs in mask, continuing\n";
}
}
else
{
echo "$i does not occur in compare mask\n";
}
}
return true;
}
// }}}
// {{{ isBoolean()
/**
* returns TRUE if $bool is a valid representation of the boolean data type
* the following are considered valid representations:
* boolean constants TRUE/FALSE
* integers 1/0
* strings '1'/'0'
* strings 'true'/'false' (not case sensitive)
* strings 't'/'f'
* strings 'yes'/'no'
* strings 'y'/'n'
* strings 'on'/'off'
*
* @param bool - The boolean string to convert
* @access public static
* @return boolean
*/
function isBoolean($bool) {
$lbool = strtolower($bool);
return (gettype($bool) == gettype(TRUE) || $bool === 1 || $bool === 0 ||
$lbool === 'true' || $lbool === 'false' || $lbool === 't' || $lbool === 'f' ||
$lbool === 'yes' || $lbool === 'no' || $lbool === 'y' || $lbool === 'n' ||
$lbool === '1' || $lbool === '0' || $lbool === 'on' || $lbool === 'off');
}
// }}}
// {{{ convertBoolean()
/**
* returns TRUE if $bool is a valid boolean data type representation of TRUE
* (see isBoolean api documentation for more details on what is considered
* a valid boolean data type representation). returns NULL if $bool is not a
* valid boolean type
* @param mixed $bool The boolean string to convert
* @param boolean $default the default value to return
* @access public static
* @return mixed
*/
function convertBoolean($bool, $default=NULL) {
return SRA_Util::isBoolean($bool) ? $bool === TRUE || $bool === 1 ||
strtolower($bool) === 'true' || strtolower($bool) === 't' ||
strtolower($bool) === 'yes' || strtolower($bool) === 'y' ||
$bool === '1' || strtolower($bool) === 'on' : $default;
}
// }}}
// {{{ extractArrayValue()
/**
* Extracts and returns the value in the array identified by the key parameter.
* Returns the return parameter (default is NULL) is that array key is not set.
*
* @param array : Object[] - The array from which the value should be
* extracted.
* @param key : String - The array key identifying the value that should be
* extracted.
* @param typeCast : String - A type cast to apply to the value. This parameter is optional. By default no type cast is applied.
* @param returnValue : Object - The value to return if the array key specified
* is not set. This is an optional parameter. The default value is NULL.
* @access public static
* @return boolean
* @author Jason Read <hide@address.com>
*/
function &extractArrayValue( & $array, $key, $typeCast = NULL, $returnValue = NULL )
{
if (!is_array($array) || !is_scalar($key))
{
return SRA_Error::logError("SRA_Util::extractArrayValue: Failed - array '" . gettype($array) .
"' parameter is not an array or key '$key' is not scalar",
__FILE__, __LINE__, SRA_ERROR_PROBLEM);
}
if (array_key_exists($key, $array))
{
switch ($typeCast)
{
case "int" :
case "integer" :
return (int) $array[$key];
case "bool" :
case "boolean" :
return (bool) $array[$key];
case "string" :
return (string) $array[$key];
case "float" :
case "double" :
case "real" :
return $array[$key];
case "array" :
return (array) $array[$key];
case "object" :
return (object) $array[$key];
default:
return $array[$key];
}
}
return $returnValue;
}
// }}}
// {{{ getArrayLocation()
/**
* Returns a reference to a location in an array containing the value specified.
* Returns an OPERATIONAL SRA_Error object if the key is not found.
*
* @param array : Object - The array to search for the value in
* @param value : String - The value to search for
* @param recursive : boolean - Optional parameter specifying whether or not
* the value should be searched for recursively. The default value for this
* parameter is false.
* @param arrayKey : String - Optional parameter specifying the element key name.
* If this parameter is not specified, the array key will be used.
* @access public static
* @return Object
* @author Jason Read <hide@address.com>
*/
function &getArrayLocation(& $array, $value, $recursive = false, $arrayKey = NULL)
{
// Validate parameters
if (!is_array($array) || !is_scalar($value) || !is_bool($recursive) || ($key && !is_scalar($key)))
{
$msg = 'SRA_Util::getArrayLocation: Failed - Invalid parameters: array: \'' . gettype($array) .
'\' value: \'' . gettype($value) . '\' recursive: \'' . gettype($recursive) . '\' key: \'' .
gettype($key) . '\'';
return(SRA_Error::logError($msg, __FILE__, __LINE__, SRA_ERROR_PROBLEM));
}
$keys = array_keys($array);
foreach ($keys as $key)
{
// Use array keys
if (!$arrayKey && $key == $value)
{
return $array[$key];
}
else if ($arrayKey && is_array($array[$key]))
{
$akeys = array_keys($array[$key]);
foreach ($akeys as $akey)
{
if ($akey == $arrayKey && !is_array($array[$key][$akey]) && $array[$key][$akey] == $value)
{
return $array[$key];
}
else if ($recursive && is_array($array[$key][$akey]))
{
if (!SRA_Error::isError($temp =& SRA_Util::getArrayLocation($array[$key][$akey], $value, true, $arrayKey)))
{
return $temp;
}
}
}
}
else if (!$arrayKey && $recursive && is_array($array[$key]))
{
if (!SRA_Error::isError($temp =& SRA_Util::getArrayLocation($array[$key], $value, true)))
{
return $temp;
}
}
}
// Array key not found
$msg = "SRA_Util::getArrayLocation: Failed - Unable to locate value '$value'";
return(SRA_Error::logError($msg, __FILE__, __LINE__, SRA_ERROR_OPERATIONAL));
}
// }}}
// {{{ getFileExtension
/**
* Returns the file extension for a given file (the string following the
* last .) or empty string if there is not extension
* @param string $fileName the file to return the extension of
* @param boolean $urlSafe whether or not to make the return value url safe
* @access public static
* @return string
*/
function getFileExtension($fileName, $urlSafe = FALSE) {
$pieces = explode('.', $fileName);
if ($urlSafe) {
return preg_replace(SRA_UTIL_URL_SAFE_REGEX, '', $pieces[count($pieces) - 1]);
}
else {
return count($pieces) > 1 ? $pieces[count($pieces) - 1] : '';
}
}
// }}}
// {{{ getFileNameWOExtension
/**
* Returns the file extension for a given file (the string following the
* last .)
* @param string $fileName the file to return the extension of
* @param boolean $urlSafe whether or not to make the return value url safe
* @access public static
* @return String
*/
function getFileNameWOExtension($fileName, $urlSafe = FALSE) {
$pieces = explode('.', basename($fileName));
$fileName = '';
$started = FALSE;
for($i=0; $i<count($pieces) - 1; $i++) {
if ($started) {
$fileName .= '.';
}
$fileName .= $pieces[$i];
$started = TRUE;
}
if ($urlSafe) {
return preg_replace(SRA_UTIL_URL_SAFE_REGEX, '', $fileName);
}
else {
return $fileName;
}
}
// }}}
// {{{ getPhpIniMemoryLimit()
/**
* This method returns the memory_limit specified in the php.ini file in
* bytes.
*
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function getPhpIniMemoryLimit()
{
$size = ini_get('memory_limit');
if ($size == "")
{
// SRA_Error.
$msg = "SRA_Util::getIniMemoryLimit() SRA_Error getting the memory_limit value from php.ini. Did you configure PHP with --enable-memory-limit?";
return(SRA_Error::logError($msg, __FILE__, __LINE__, SRA_ERROR_PROBLEM));
}
$scan['MB'] = 1048576;
$scan['M'] = 1048576;
$scan['KB'] = 1024;
$scan['K'] = 1024;
while (list($key) = each($scan))
{
if ((strlen($size) > strlen($key)) && (substr($size,strlen($size) - strlen($key))==$key))
{
$size = substr($size, 0, strlen($size) - strlen($key)) * $scan[$key];
break;
}
}
return($size);
}
// }}}
// {{{ getPrefixedArrayValues
/**
* returns a sub-array containing all of the values in $arr that are
* are prefixed with $prefix
* @param string $prefix the prefix value
* @param array $arr the array to search
* @param boolean $removePrefix whether or not to remove $prefix from the
* return values. default is TRUE
* @return array
*/
function &getPrefixedArrayValues($prefix, $arr, $removePrefix=TRUE) {
$newArr = array();
foreach($arr as $val) {
if (strpos($val, $prefix) === 0) {
$newArr[] = $removePrefix ? substr($val, strlen($prefix)) : $val;
}
}
return $newArr;
}
// }}}
// {{{ getCurrentUser
/**
* same as the php 'get_current_user' function but returns the correct
* username for child processes (the 'get_current_user' function returns the
* username for the parent process even if the child process owner is
* different)
* @return string
*/
function getCurrentUser() {
$tmp = posix_getpwuid(posix_geteuid());
return $tmp['name'];
}
// }}}
// {{{ getProcessAttr
/**
* returns a process attribute
* @param string $attr the attribute to return. some examples of attributes
* are: %cpu, %mem, egid, egroup, etime, euid, euser, ppid, args. for more
* information, see the man page for 'ps'
* @param int $pid the pid of the process. if not specified, the pid of the
* current running process will be used
* @return string
*/
function getProcessAttr($attr, $pid=NULL) {
$pid = $pid ? $pid : getmypid();
$rattr = NULL;
exec(SRA_File::findInPath(SRA_PS_PATH) . ' -p ' . $pid . ' -o "pid ' . $attr . '"', $processes);
foreach ($processes as $process) {
$process = trim($process);
if ($pid == substr($process, 0, strpos($process, ' '))*1) {
$rattr = trim(substr($process, strpos($process, ' ')+1));
}
}
return $rattr;
}
// }}}
// {{{ getProcessHash
/**
* returns a hash of the currently running processes where the key is the pid
* and the value is the process command
* @param string $val the process value to use as the hash value. the default
* value is the process command. alternatively, any of the "ps" output value
* identifiers may be specified
* @return hash
*/
function getProcessHash($val='command') {
$hash = array();
exec(SRA_File::findInPath(SRA_PS_PATH) . ' -A -w -o "pid ' . $val . '"', $processes);
foreach ($processes as $process) {
$process = trim($process);
$pid = substr($process, 0, strpos($process, ' '))*1;
$cmd = substr($process, strpos($process, ' ') + 1);
$hash[$pid] = $cmd;
}
return $hash;
}
// }}}
// {{{ getProcessId
/**
* this method returns the pid of the $script process. NULL is returned if
* no process currently exists. if $multiple is TRUE, the return value will be
* an array containing all of the matching pids (or NULL if none)
* @param string $script the name of the script, either the full path or
* just the name
* @param boolean $last whether or not the pid of the oldest or most recent
* process should be returned if multiple are running
* @param mixed $user an optional uid or username to limit the search to (only
* processes owned by this user will be returned)
* @param boolean $multiple whether or not to return multiple pids if they
* exist (return value will be an array)
* @return mixed
*/
function getProcessId($script, $last=TRUE, $user=NULL, $multiple=FALSE) {
if ($multiple) { $pids = array(); }
$script = basename($script);
$script = strlen($script) > 15 ? substr($script, strlen($script) - 15) : $script;
if ($script) {
$processes = SRA_Util::getProcessHash(isset($user) ? 'uid user command' : 'command');
if ($last) { $processes = array_reverse($processes, TRUE); }
foreach ($processes as $pid => $cmd) {
if (isset($user)) {
$pieces = explode(' ', trim($cmd));
if ($user != trim($pieces[0]) && $user != trim($pieces[1])) { continue; }
}
if (strpos($cmd, $script) !== FALSE) {
if ($multiple) {
$pids[] = $pid;
}
else {
return $pid;
}
}
}
}
return $multiple && $pids ? $pids : NULL;
}
// }}}
// {{{ getProcessName
/**
* returns the name of the process identified by $pid. returns NULL if $pid is
* not a valid process. the name of the process is the "command" keyword from
* ps
* @param int $pid the id of the process
* @return mixed
*/
function getProcessName($pid) {
return SRA_Util::getProcessAttr('args');
}
// }}}
// {{{ getRelativeNumericVal
/**
* returns the numeric value for a relative $expr where $expr is in the format
* "+n" and n may be designated as negative by enclosing it in parenthesis
* @param string $expr the expression value to return
* @access public static
* @return int
*/
function getRelativeNumericVal($expr) {
$expr = SRA_Util::beginsWith($expr, '+') ? substr($expr, 1) : $expr;
return SRA_Util::beginsWith($expr, '(') && SRA_Util::endsWith($expr, ')') ? -1 * substr($expr, 1, -1) : 1 * $expr;
}
// }}}
// {{{ getSpellCheckLanguages
/**
* returns the spellcheck languages as an associative array where the key is
* the locale code (see SRA_Locale::getLocale($code...)), and the value is
* the locale label (see SRA_Locale::getLabel()). returns NULL if aspell is
* not available or if the dictionary path cannot be determined or read from
* @access public static
* @return array
*/
function &getSpellCheckLanguages() {
if ($aspell = SRA_File::findInPath(SRA_UTIL_ASPELL)) {
// determine dictionary directory
exec($aspell . ' config dict-dir', $results);
if (isset($results[0]) && is_dir($results[0]) && is_readable($results[0])) {
$languages = array();
$files = SRA_File::getFileList($results[0], '/^.*.multi$/');
foreach($files as $file) {
$code = str_replace('.multi', '', basename($file));
if ((strlen($code) == 2 || strlen($code) == 5) && SRA_Locale::isValid($locale =& SRA_Locale::getLocale($code))) {
$languages[strtolower($code)] = strlen($code) == 2 ? $locale->getLanguageName() : $locale->getLabel();
}
}
return $languages;
}
}
return NULL;
}
// }}}
// {{{ getDefaultSpellCheckLanguage
/**
* returns the default spell check language code for the current active user
* this is done by first accessing the spellcheck languages using
* SRA_Util::getSpellCheckLanguages() followed by the user's locales using
* SRA_Controller::getUserLocales(), and then finding the first match in the
* spellcheck languages that exists in the user's locales. if not match is
* found the first spell check language will be returned. if there are no
* spellcheck languages NULL will be returned
*
* @access public static
* @return String
*/
function getDefaultSpellCheckLanguage() {
$dictionaries =& SRA_Util::getSpellCheckLanguages();
if ($dictionaries) {
$locales =& SRA_Controller::getUserLocales();
$keys = array_keys($locales);
foreach($keys as $key) {
$code = $locales[$key]->getLanguage() . '_' . $locales[$key]->getCountry();
if (isset($dictionaries[$code])) {
return $code;
}
else if (isset($dictionaries[$locales[$key]->getLanguage()])) {
return $locales[$key]->getLanguage();
}
}
$keys = array_keys($dictionaries);
return $keys[0];
}
return NULL;
}
// }}}
// {{{ getEnglishOrdinalSuffix
/**
* returns the english ordinal suffix for $number (st, nd, rd, or th)
* @param int $number the number to return the ordinal suffix for
* @access publicstatic
* @return String
*/
function getEnglishOrdinalSuffix($number) {
$suffix = '';
if (is_numeric($number)) {
$ln = (int) substr($number, -1);
$sln = (int) substr($number, -2);
$r = array('st','nd','rd');
$es = (($sln < 11 || $sln > 19) && $ln > 0 && $ln < 4);
$suffix = $es ? $r[$ln - 1] : 'th';
}
return $suffix;
}
// }}}
// {{{ getTextBetween()
/**
* Returns a substring of the text provided that is between the startToken
* and the endToken
*
* @param startToken. String - the start string. If this start token is
* not found the returned text will start at the beginning of the
* text
* @param endToken. String - the end string. If this end token is not
* found, the returned text will end at the end of the text.
* @param text. String - the text
* @access public static
* @return String
* @author Jason Read <hide@address.com>
*/
function &getTextBetween( $startToken, $endToken, & $text )
{
$startPos = strpos($text, $startToken);
if (!$startPos) {
$startPos = 0;
}
else {
$startPos += strlen($startToken);
}
$endPos = strpos($text, $endToken, $startPos);
if (!$endPos) {
$endPos = strlen($text);
}
return substr($text, $startPos, $endPos - $startPos);
}
// }}}
// {{{ htmlToText()
/**
* This method is used to convert html to plain text (no html tags)
*
* @param html - The html text to convert to text
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function htmlToText( $html )
{
$search = array ("'<script[^>]*?>.*?</script>'si", // Strip out javascript
"'<[\/\!]*?[^<>]*?>'si", // Strip out html tags
"'([\r\n])[\s]+'", // Strip out white space
"'&(quot|#34);'i", // Replace html entities
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i",
"'&#(\d+);'e"); // evaluate as php
$replace = array ("",
"",
"\\1",
"\"",
"&",
"<",
">",
" ",
chr(161),
chr(162),
chr(163),
chr(169),
"chr(\\1)");
return preg_replace ($search, $replace, $html);
}
// }}}
// {{{ implodeSkipEmpty
/**
* same as the php implode function but skips $pieces values that are empty
* (do not evaluate to PHP true)
* @param string $glue the string to insert between each value in $pieces
* @param array $pieces the array to implode
* @param boolean $lead whether or not to lead the return value with $glue
* if it is not empty
* @param boolean $trim whether or not to trim the values in $pieces
* @access public static
* @return string
*/
function implodeSkipEmpty($glue, $pieces, $lead=FALSE, $trim=TRUE) {
$value = '';
foreach($pieces as $piece) {
if ($trim) { $piece = trim($piece); }
if ($piece) {
$value .= $value != '' ? $glue : '';
$value .= $piece;
}
}
return $lead && $value ? $glue . $value : $value;
}
// }}}
// {{{ includeAttributeInOutput
/**
* returns TRUE if ($include is an array and $attr is in it or if $include
* is not an array) and ($exclude is an array and $attr is not in it or if
* $exclude is not an array)
*
* @param string $attr the name of the attribute to check
* @param mixed $include the include array. may include nested values
* for entity type attributes delimited by '_'
* @param mixed $exclude the exclude array. may include nested values
* for entity type attributes delimited by '_'
* @return boolean
*/
function includeAttributeInOutput($attr, $include, $exclude) {
$found = TRUE;
if (is_array($include)) {
$found = FALSE;
foreach($include as $id) {
if ($attr == $id || strpos($id, $attr . '_') === 0) { $found = TRUE; break; }
}
}
if (!$found) { return FALSE; }
if (is_array($exclude)) {
foreach($exclude as $id) {
if ($attr == $id || strpos($id, $attr . '_') === 0) { return FALSE; }
}
}
return TRUE;
}
// }}}
// {{{ isProcessActive
/**
* returns TRUE if a process identified by $pid is currently active
* @param int $pid the id of the process
* @return boolean
*/
function isProcessActive($pid) {
return preg_match('/' . $pid . '/', shell_exec(SRA_File::findInPath(SRA_PS_PATH) . ' -p ' . $pid)) ? TRUE : FALSE;
}
// }}}
// {{{ isSubclassOf()
/**
* This method is very simliar to the built in php is_subclass_of function with the
* exception that the object parameter may be either an object or a class name
* (php function requires it to be an object). This method returns true if the
* parent parameter class type is a class that the child parameter extends from.
*
* @param parent : Object - The parent object or class name. This parameter must
* be passed as a variable (i.e. "MyClass" wll not work...
* instead use $temp = "MyClass").
* @param child : Object - The child object or class name. This parameter must
* be passed as a variable (i.e. "MyClass" wll not work...
* instead use $temp = "MyClass").
* @access public static
* @return boolean
* @author Jason Read <hide@address.com>
*/
function isSubclassOf( & $parent, & $child )
{
if (is_object($parent))
{
$parent = get_class($parent);
}
if(is_string($child))
{
do
{
$child = get_parent_class($child);
// Not a child class
if(!$child){
return false;
}
} while ($child==$parent);
return true;
}
// Use standard php function
else
{
return is_subclass_of($child, $parent);
}
}
// }}}
// {{{ killProcess
/**
* kills $pid if it is active. returns TRUE on success, FALSE if the kill
* fails, and NULL if $pid is not valid
* @param int $pid the process id to kill
* @access public
* @return boolean
*/
function killProcess($pid) {
if (SRA_Util::isProcessActive($pid)) {
exec('kill -9 ' . $pid);
return SRA_Util::isProcessActive($pid);
}
return NULL;
}
// }}}
// {{{ objToArray
/**
* returns the attributes associated with an object as an associative array
* where the array index is the attribute name. all leading underscores are
* removed from the attribute names. only attributes with leading underscores
* are included in the returned array
*
* @param obj : Object - the object to return the array for
* @access public
* @return array
*/
function &objToArray(& $obj) {
$attrs = array();
$keys = array_keys(get_object_vars($obj));
if (is_array($keys)) {
foreach ($keys as $key) {
if (substr($key, 0, 1) == '_') {
$attrs[substr($key, 1, strlen($key))] = $obj->{$key};
}
}
}
return $attrs;
}
// }}}
// {{{ parseEmailString
/**
* used to parse an email string and return the corresponding name and email
* values from the string. an email string may be in any of the following
* formats:
* hide@address.com
* <hide@address.com>
* John Doe <hide@address.com>
* "John Doe" <hide@address.com>
* the return value will be a hash with the keys 'email' and 'name' where
* those values were extracted from the email string provided. name may not
* be present in the return value if it is not part of the email string
* @param string $str the email string to parse
* @access public
* @return array
*/
function parseEmailString($str) {
$pieces = explode(' ', $str);
$email = $pieces[count($pieces) - 1];
$email = SRA_Util::stripQuotes($email, '<', '>');
if (count($pieces) > 1) {
$name = '';
for($i=0; $i<count($pieces) - 1; $i++) {
$name .= ($i > 0 ? ' ' : '') . $pieces[$i];
}
$name = SRA_Util::stripQuotes($name);
$name = SRA_Util::stripQuotes($name, "'", "'");
}
$results = array();
if ($email) {
$results['email'] = $email;
}
if ($name) {
$results['name'] = $name;
}
return $results;
}
// }}}
// {{{ printDebug()
/**
* This method displays a debug statement followed by a newline character if the debug parameter
* is true. If no debug statement is specified it checks the SRA_Controller::DEBUG constant. If this
* is true, it displays the debug info.
*
* @param output - The debug output. If this is an array or object, it will be printed using print_r
* @param debug - The debug boolean flag. if not specified, the SRA_Controller::isAppInDebug() method will be
* called to determine if debug output should be produced
* @param file - The file where the debug message originated from (optional).
* @param line - The line number where the debug message originated from (optional).
* @param pre - Boolean. Wrap the output in <pre></pre> tags for display in browser (optional).
* @param quiet - Whether or not the output should be quiet... meaning, only the output is displayed, followed by a newline
* @param traceFile - an optional file to output to
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function printDebug( $output, $debug=SRA_UTIL_USE_SYS_CONFIG_DEBUG, $file="", $line=0, $pre=false, $quiet=false, $timestamp=false, $traceFile=false )
{
$buffer = '';
if ($timestamp) {
$buffer .= date('Y-m-d H:i:s', mktime()) . ' ';
}
if ($debug === SRA_UTIL_USE_APP_CONFIG_DEBUG) {
$debug = SRA_Controller::isAppInDebug();
}
else if ($debug === SRA_UTIL_USE_SYS_CONFIG_DEBUG) {
$debug = SRA_Controller::isSysInDebug();
}
if ($debug) {
if ($quiet) {
$buffer = $output . "\n";
}
else {
if ($pre) {
$buffer .= '<pre>';
}
$buffer .= 'DEBUG: ';
if ($file != "") {
$file=explode("/", $file);
$buffer .= 'SRA_File: ' . $file[count($file)-1] . ', ';
}
if ($line>0) {
$buffer .= 'Line: ' . $line . ', ';
}
$type = gettype($output);
if ($type == 'array' || $type == 'object') {
ob_start();
print_r($output);
$buffer .= ob_get_contents();
ob_end_clean();
}
else {
$buffer .= $output . "\n";
}
if ($pre) {
$buffer .= '</pre>';
}
}
}
if (!$traceFile) {
echo $buffer;
}
else {
$fp = fopen($traceFile, 'a');
fwrite($fp, $buffer);
fclose($fp);
}
}
// }}}
// {{{ rand()
/**
* wrapper for the php rand function (for use in templates)
* @param int $min min value
* @param int $max max value
* @access public static
* @return int
*/
function rand($min, $max) {
return rand($min, $max);
}
// }}}
// {{{ removeDelimString()
/**
* This method is used remove a delimeter string added through the addDelimString method..
*
* @param string - The String to remove the delimeter string from
* @param delim - The delimeter to replace the delimeter string with. The default is a comma.
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function removeDelimString( $string, $delim="," )
{
return str_replace("<delim>", $delim, $string);
}
// }}}
// {{{ replaceArrayKey()
/**
* This method is used replace an array key. It simply unsets the array element with the key
* identified by the oldKey parameter and adds the value at that element to a new key identified
* by the newKey parameter. If the oldKey does not exist, or the newKey does, the array will be
* returned as is.
*
* @param arr - The array to replace the key in.
* @param oldKey - The key to be replaced
* @param newKey - The key to add
* @param caseSensitive - Whether or not the comparison should be case sensitive
* @access public static
* @return String[]
* @author Jason Read <hide@address.com>
*/
function &replaceArrayKey( & $arr, $oldKey, $newKey, $caseSensitive=TRUE )
{
if (!array_key_exists($newKey, $arr))
{
$arrKeys = array_keys($arr);
foreach ($arrKeys as $key)
{
$unset=false;
if ($caseSensitive)
{
if ($key == $oldKey)
$unset=true;
}
else
{
if (strtolower($key) == strtolower($oldKey))
$unset=true;
}
if ($unset)
{
$arr[$newKey]=$arr[$oldKey];
unset($arr[$oldKey]);
break;
}
}
}
}
// }}}
// {{{ sendEmail
/**
* sends an email message based on the following parameters:
*
* @param mixed $to the recipient email address. if $to is an array, 1
* message will be sent to each recipient. multiple messages can be sent to
* in the same message instance by separating each recipient with a comma
* (i.e. "hide@address.com, Jason <hide@address.com>")
* @param string $subject the email subject
* @param string $message the text version of the email message. either
* $message or $messageHtml MUST be specified. if both are specified, the
* message will be sent with both content types. otherwise, only the content
* type specified will be sent
* @param string $messageHtml the html version of the email message
* @param string $from the sender email address. if not specified, the
* default from address will be used ([process user]@[server domain])
* @param string $fromName the sender name (optional). can also be specified
* in $from using the syntax "[email] <[name]>"
* @param mixed $toName the recipient name (optional). if $to is an array,
* and $toName is specified, it much also be an array with the same # of
* values. can also be specified in $from using the syntax
* "[email] <[name]>"
* @param string $cc optional comma separated list of carbon copy recipients
* @param string $bcc optional comma separated list of blind carbon copy
* recipients
* @param mixed $attachments a single file absolute path/SRA_FileAttribute
* object or array of absolute file paths/SRA_FileAttribute objects that
* should be attached to this email. the names assigned to these attachments
* will be the names of the files themselves. content type must be able to
* be determined based on the file extension (for paths - the extension must
* have a corresponding content type in /etc/mime.types). NOTE: if a key in
* this array is not numeric, that attachment will be considered to be
* inline where the Content-ID is the array key. This feature may be useful
* in order to imbed images that will be referenced in the html formatted
* email using <img src="cid:[Content-ID]" />
* @access public static
* @return void
*/
function sendEmail($to, $subject, $message=NULL, $messageHtml=NULL, $from=NULL, $fromName=NULL, $toName=NULL, $cc=NULL, $bcc=NULL, &$attachments) {
$to = !is_array($to) ? array($to) : $to;
$toName = $toName && !is_array($toName) ? array($toName) : $toName;
$from = $from ? ($fromName ? $fromName . ' <' . $from . '>' : $from) : NULL;
if ($attachments && !is_array($attachments)) {
$tmp = array();
$tmp[] =& $attachments;
$attachments =& $tmp;
}
// make sure content-types are valid available for attachments
if ($attachments) {
$keys = array_keys($attachments);
foreach($keys as $key) {
if (!SRA_FileAttribute::isValid($attachments[$key])) {
if (!file_exists($attachments[$key]) || !is_readable($attachments[$key])) {
SRA_Error::logError('SRA_Util::sendEmail: Attachment "' . $attachments[$key] . '" will not be included in email message because it does not exist, or it is not readable', __FILE__, __LINE__);
unset($attachments[$key]);
}
else if (SRA_Error::isError(SRA_File::getMimeType($attachments[$key]))) {
SRA_Error::logError('SRA_Util::sendEmail: Attachment "' . $attachments[$key] . '" will not be included in email message because a content type cannot be determined for it', __FILE__, __LINE__);
unset($attachments[$key]);
}
}
}
}
$keys = array_keys($to);
foreach($keys as $key) {
$headers = $from ? 'From: ' . $from . "\n" : '';
$headers .= 'Return-Path: ' . $from . "\n";
$headers .= $cc ? "Cc: ${cc}\n" : '';
$headers .= $bcc ? "Bcc: ${bcc}\n" : '';
$mimeMessage = ($message && $messageHtml) || $attachments;
if ($mimeMessage) {
$boundary = '==Multipart_Boundary_' . md5(uniqid(time()));
$headers .= 'MIME-Version: 1.0' ."\n";
$headers .= 'Content-Type: multipart/' . ($attachments ? 'mixed' : 'alternative') . '; boundary="' . $boundary . '"' . "\n\n";
$headers .= 'This is a multi-part message in MIME format.' . "\n";
}
if ($message) {
$headers .= $mimeMessage ? '--' . $boundary . "\n" : '';
$headers .= 'Content-Type: text/plain; charset=ISO-8859-1' ."\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\n";
$headers .= $message . "\n";
}
if ($messageHtml) {
$headers .= $mimeMessage ? '--' . $boundary . "\n" : '';
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' ."\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\n";
$headers .= $messageHtml . "\n";
}
if ($attachments) {
$akeys = array_keys($attachments);
foreach($akeys as $akey) {
if (!SRA_FileAttribute::isValid($attachments[$akey])) {
$fileName = basename($attachments[$akey]);
$headers .= '--' . $boundary . "\n";
$headers .= 'Content-Type: ' . SRA_File::getMimeType($attachments[$akey]) . ";\n";
$headers .= " name=\"$fileName\"\n";
$headers .= 'Content-Disposition: ' . (is_numeric($akey) ? 'attachment' : 'inline') . ";\n";
$headers .= " filename=\"$fileName\"\n";
$headers .= "Content-Transfer-Encoding: base64\n";
$headers .= is_numeric($akey) ? '' : "Content-ID:<$akey>\n";
$headers .= "\n";
$fp = fopen($attachments[$akey], 'rb');
$headers .= chunk_split(base64_encode(fread($fp, filesize($attachments[$akey])))) . "\n\n";
fclose($fp);
}
else {
$headers .= '--' . $boundary . "\n";
$headers .= 'Content-Type: ' . $attachments[$akey]->getType() . ";\n";
$headers .= ' name="' . $attachments[$akey]->getName() . "\"\n";
$headers .= 'Content-Disposition: ' . (is_numeric($akey) ? 'attachment' : 'inline') . ";\n";
$headers .= ' filename="' . $attachments[$akey]->getName() . "\"\n";
$headers .= "Content-Transfer-Encoding: base64\n";
$headers .= is_numeric($akey) ? '' : "Content-ID:<$akey>\n";
$headers .= "\n";
$headers .= chunk_split(base64_encode($attachments[$akey]->getBytes())) . "\n\n";
}
}
}
$headers .= $mimeMessage ? '--' . $boundary . "--\n" : '';
$recipient = $toName && $toName[$key] ? $toName[$key] . ' <' . $to[$key] . '>' : $to[$key];
mail($recipient, $subject,'', $headers);
}
}
// }}}
// {{{ spellcheck
/**
* used to spellcheck $str. the return value is an associative array with
* the following values:
* word: the word that was mispelled
* suggestions: an array containing correction suggestion (NULL if none)
* offsets: character positions in $str where the mispelling occured
* (will contain 1 or more character positions if mispelled
* multiple times)
* this array will be indexed by "word". if aspell is not enabled, or
* another error occurs, this method will will return NULL
* @param string $str the string to spellcheck. alternatively, $str may be
* a file path
* @param string $lang the language code. this MUST be one of the language
* codes returned by getSpellCheckLanguages. if not valid, or not specified,
* SRA_Util::getDefaultSpellCheckLanguage will be used
* @param boolean $html whether or not to perform the spellcheck in html
* mode (html tags will be ignored)
* @param array $skip optional array of words to skip if misspelled
* @access public static
* @return array
*/
function spellcheck($str, $lang=NULL, $html=FALSE, $skip=NULL) {
if ($aspell = SRA_File::findInPath(SRA_UTIL_ASPELL)) {
$lang = $lang ? $lang : SRA_Util::getDefaultSpellCheckLanguage();
$delete = FALSE;
if (is_file($str)) {
$str = SRA_File::toString($str);
}
$file = SRA_File::createRandomFile(FALSE, "", "", str_replace("\n", '^', $str));
$options = ' --lang=' . $lang . ' -a' . ($html ? ' -H' : '') . ' < ';
exec($aspell . $options . $file, $output);
SRA_File::unlink($file);
$results = array();
$keys = array_keys($output);
foreach($keys as $key) {
$eval = substr($output[$key], 0, 1);
if ($eval == '&' || $eval == '?' || $eval == '#') {
$pieces = explode(':', $output[$key]);
$head = explode(' ', $pieces[0]);
if (!is_array($skip) || !in_array($head[1], $skip)) {
if (!isset($results[$head[1]])) {
$results[$head[1]] = array('word' => $head[1], 'suggestions' => (isset($pieces[1]) ? explode(', ', $pieces[1]) : NULL), 'offsets' => array());
if (isset($pieces[1])) { $results[$head[1]]['suggestions'][0] = trim($results[$head[1]]['suggestions'][0]); }
}
$results[$head[1]]['offsets'][] = $head[count($head) - 1];
}
}
}
return $results;
}
return NULL;
}
// }}}
// {{{ stripQuotes()
/**
* This method is used to strip quotes (or another quote token) from a string. It returns the stripped string
*
* @param string - The String to strip the quotes from.
* @param quoteTokenStart - The start quote token to strip (by default this is a double quote)
* @param quoteTokenEnd - The end quote token to strip (by default this is a double quote)
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function stripQuotes( $string, $quoteTokenStart='"', $quoteTokenEnd='"' )
{
if (strlen($string)<3)
{
if ($string == $quoteTokenStart . $quoteTokenEnd)
return "";
else
return $string;
}
if (substr($string, 0, 1) == $quoteTokenStart && substr($string, strlen($string)-1, 1) == $quoteTokenEnd)
{
return substr($string, 1, strlen($string)-2);
}
else
{
return $string;
}
}
// }}}
// {{{ strToHtml
/**
* replaces linebreaks with html <br /> tags and other special html
* characters to HTML entities
* @param string $str the string to convert
* @access public static
* @return void
*/
function strToHtml($str) {
return str_replace("\n", '<br />', htmlspecialchars($str));
}
// }}}
// {{{ swapValues()
/**
* Swaps two values
*
* @param currVal : String - The current value (this is a reference parameter
* @param firstVal : String - The first value
* @param seconVal : String - The second value
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function swapValues( & $currVal, $firstVal, $secondVal )
{
if (!$currVal || $currVal == $secondVal)
{
$currVal = $firstVal;
}
else
{
$currVal = $secondVal;
}
}
// }}}
// {{{ writeHttpToFile()
/**
* This method is used to write an http request to a file. To do this it extracts all of the
* related data from the GLOBAL variables $_POST, $_GET, $_COOKIE, $_SERVER, and $_ENV
* and writes them to a file containing arrays specifying these values. The optional errorMsg
* attribute may be specified to have an errorMsg array attribute added to the 'values' array (the
* array in which all of the values are stored) along with the other globals ('_POST', '_GET', etc.).
*
* @param file - The file where the data should be saved.
* @param errorMsg - An optional error message that will be added to the array if specified.
* @access public static
* @return void
* @author Jason Read <hide@address.com>
*/
function writeHttpToFile( $file, $errorMsg="" )
{
if ($fp = fopen($file, "w"))
{
fwrite ($fp, "<?php\n");
fwrite ($fp, "\$values = array(\n");
fwrite ($fp, "'errorMsg' => '" . str_replace("'", "\\'", $errorMsg) . "', \n");
fwrite ($fp, "'_POST' => " . SRA_Util::bufferArray($_POST) . ", \n");
fwrite ($fp, "'_GET' => " . SRA_Util::bufferArray($_GET) . ", \n");
fwrite ($fp, "'_COOKIE' => " . SRA_Util::bufferArray($_COOKIE) . ", \n");
fwrite ($fp, "'_SERVER' => " . SRA_Util::bufferArray($_SERVER) . ", \n");
fwrite ($fp, "'_ENV' => " . SRA_Util::bufferArray($_ENV) . " \n");
fwrite ($fp, ");\n?>");
fclose($fp);
}
else
{
SRA_Error::logError("Utl::writeHttpToFile() failed: Unable to open file '{$file}'", __FILE__, __LINE__, SRA_ERROR_PROBLEM);
}
}
// }}}
// {{{ validateBit()
/**
* Returns true if the bit parameter specified is a single bit in the fullBitMask parameter.
*
* @param bit : int - The bit to validate.
* @param fullBitMask : int - The bitmask to validate against.
* @access public static
* @return boolean
* @author Jason Read <hide@address.com>
*/
function validateBit($bit, $fullBitMask) {
$bit = is_numeric($bit) && !is_int($bit) ? (int) $bit : $bit;
$fullBitMask = is_numeric($fullBitMask) && !is_int($fullBitMask) ? (int) $fullBitMask : $fullBitMask;
// Both parameter must be integers
if (!is_int($bit) || !is_int($fullBitMask)) {
return FALSE;
}
return (($bit & $fullBitMask) == $bit);
}
// }}}
// {{{ validateEmail
/**
* returns TRUE if an email address is properly constructed, FALSE otherwise
* @param string $email the email address to validate
* @access public static
* @return boolean
*/
function validateEmail($email) {
return ereg("^([0-9,a-z,A-Z]+)([.,_]([0-9,a-z,A-Z]+))*[@]([0-9,a-z,A-Z]+)([.,_,-]([0-9,a-z,A-Z]+))*[.]([0-9,a-z,A-Z]){2}([0-9,a-z,A-Z])?$",$email);
}
// }}}
// {{{ ipv4ToLong
/**
* converts an IP address to it's corresponding numeric value
* @param string $ip the ip address (ipv4 or ipv6) to convert
* @access public
* @return long
*/
function ipv4ToLong($ip) {
include_once('model/SRA_AttributeValidator.php');
$num = NULL;
if (SRA_AttributeValidator::ipv4($ip)) {
$ipArr = explode('.', $ip);
$num = ($ipArr[0] * 0x1000000) + ($ipArr[1] * 0x10000) + ($ipArr[2] * 0x100) + ($ipArr[3]);
}
return $num;
}
// }}}
// {{{ longToIpv4
/**
* converts a numeric IPv4 address to dot notation
* @param long $num the IP number to convert
* @access public
* @return string
*/
function longToIpv4($num) {
$ipArr = array(0 => floor($num/0x1000000));
$ipArr[1] = ($num & 0xFF0000) >> 16;
$ipArr[2] = ($num & 0xFF00 ) >> 8;
$ipArr[3] = $num & 0xFF;
return implode('.', $ipArr);
}
// }}}
// {{{ validateIp
/**
* This method is used to validate an IP address against an array of valid IPs. If the IP
* address is valid it returns true. Otherwise it returns false.
*
* @param array $validateAddresses an array of valid IP addresses. This array may contain
* wild card values for any of the ip address sub-nets. For example, to allow all IP
* addresses in the 192.168.1.0 network, the value in this array would be 192.168.1.*.
* If not restriction is desired, this array should consist of a single value: '*'.
*
* @param string $validateAddress optional parameter specifying the IP address to validate.
* If this parameter is not specified the current IP address in the globals $_SERVER
* array will be used ($_SERVER['REMOTE_ADDR']).
*
* @access public
* @return boolean
*/
function validateIp( $validateAddresses, $validateAddress=false )
{
if ($validateAddresses && !is_array($validateAddresses)) { $validateAddresses = array($validateAddresses); }
if (is_array($validateAddresses))
{
if (in_array("*", $validateAddresses))
{
return true;
}
if (!$validateAddress)
{
$validateAddress = $_SERVER['REMOTE_ADDR'];
}
if (!$validateAddress)
{
SRA_Error::logError("Utl::validateIp() failed: validateAddress not specified and not available through _SERVER global.",
__FILE__, __LINE__, SRA_ERROR_PROBLEM);
return false;
}
$ipBits = explode(".", $validateAddress);
for ($i=0; $i< count($ipBits); $i++)
{
$ip = "";
for ($n=0; $n<=$i; $n++)
{
$ip .= $ipBits[$n];
if ($n != count($ipBits) - 1)
$ip .= ".";
}
for ($n=$i; $n<count($ipBits) - 1; $n++)
{
if ($n != 0 && $n != $i)
{
$ip .= ".";
}
$ip .= "*";
}
if (in_array($ip, $validateAddresses))
{
return true;
}
}
return false;
}
else
{
SRA_Error::logError("Utl::validateIp() failed: Invalid validateAddresses parameter.",
__FILE__, __LINE__, SRA_ERROR_PROBLEM);
return false;
}
}
// }}}
// {{{ sortObjects
/**
* used to sort objects based on a given attribute
* @param object[] objects - the array of objects to sort. the array index
* associations will be maintained by this method. alternatively, this may be
* an array of associative arrays
* @param string getter - the name of the getter method, object attribute or
* array index to sort on
* @param boolean desc - whether or not to sort the objects in descending order
* the default is ascending order
* @param int $maintainKeys whether or not to maintain the array keys or reset
* them in the returned sorted array
* @return object[]
*/
function &sortObjects(&$objects, $getter, $desc = TRUE, $maintainKeys=TRUE) {
$keys = array_keys($objects);
$key = $keys[0];
if (is_object($objects[$key])) {
if (method_exists($objects[$key], $getter)) {
$isAttr = FALSE;
}
else if (method_exists($objects[$key], $tmp = 'get' . strtoupper(substr($getter, 0, 1)) . substr($getter, 1))) {
$isAttr = FALSE;
$getter = $tmp;
}
else if (in_array('_' . $getter, get_class_vars(get_class($objects[$key])))) {
$getter = '_' . $getter;
$isAttr = TRUE;
}
else {
$isAttr = TRUE;
}
}
$sortVals = array();
foreach ($keys as $key) {
$val = is_object($objects[$key]) ? (!$isAttr && method_exists($objects[$key], $getter) ? $objects[$key]->{$getter}() : (isset($objects[$key]->{$getter}) ? $objects[$key]->{$getter} : $objects[$key]->_{$getter})) : $objects[$key][$getter];
$sortVals[$key] = $val;
}
if ($desc) {
arsort($sortVals);
}
else {
asort($sortVals);
}
$sorted = array();
$keys = array_keys($sortVals);
foreach ($keys as $key) {
if ($maintainKeys) {
$sorted[$key] =& $objects[$key];
}
else {
$sorted[] =& $objects[$key];
}
}
return $sorted;
}
// }}}
// {{{ getCondValFromTable
/**
* Used to return a value from a two dimensional table
* @param array[][] table - the table to evaluate
* @param int condValCol - the conditional value column
* @param String condVal - the conditional value
* @param int valCol - the value column
* @return String
*/
function getCondValFromTable($table, $condValCol, $condVal, $valCol) {
$keys = array_keys($table);
foreach ($keys as $key) {
if ($table[$key][$condValCol] == $condVal) {
return $table[$key][$valCol];
}
}
return FALSE;
}
// }}}
// {{{ getFixedWidthString
/**
* Used to add padding to a string so that it conforms with a specified width
* @param String string - the string to pad
* @param int width - the desired fixed width of the string
* @return String
*/
function getFixedWidthString($string, $width = FALSE) {
if (is_array($string)) {
$width = $string['width'];
$string = $string['string'];
}
if ($width > strlen($string)) {
for ($i=strlen($string); $i<$width; $i++) {
$string .= ' ';
}
}
return $string;
}
// }}}
// {{{ objectToString
/**
* Converts an object instance into a string representation using the print_r
* function and output buffering (ob_start)
* @param object : Object - the object to convert
* @return String
*/
function &objectToString(& $object) {
ob_start();
print_r($object);
$string =& ob_get_contents();
ob_end_clean();
return $string;
}
// }}}
// {{{ copyObject
/**
* Creates a copy of an object
* @param object : Object - the object to copy
* @return Object
*/
function copyObject($object) {
return $object;
}
// }}}
// {{{ removeLeadingSlash
/**
* removes a leading slash from a string
* @param string : $str - the string to remove the leading slash from
* @return string
*/
function removeLeadingSlash($str) {
if (substr($str, 0, 1) == '/') {
return substr($str, 1);
}
return $str;
}
// }}}
// {{{ getObjectAttr
/**
* gets the attribute specified from the baseObj if it exists
*
* @param mixed $baseObj the base object or array to start from
* @param string $attrId the attribute identifies. this may be a combinantion
* of sub-methods and array indices. methods must not require parameters.
* for example, attrId "getMailingAddress->getStreet.line1" would return line 1
* of the mailing address for object $baseObj assuming that getStreet returned
* some form of Address object containing a getStreet method. Additionally, if
* getMaillingAddress had returned multiple Address objects, the return value
* would be an array containing all of the line 1 strings for those addresses
* @return mixed
*/
function getNestedAttr(& $baseObj, $attrId) {
$pieces = explode('->', $attrId);
$keys = array();
foreach ($pieces as $piece) {
$keys[] = explode('.', $piece);
}
$var = $baseObj;
for($i=0; $i<count($keys); $i++) {
for($n = 0;$n<count($keys[$i]); $n++) {
$key = $keys[$i][$n];
$vkeys = is_array($var) ? array_keys($var) : FALSE;
if (is_object($var) && method_exists($var, $key)) {
$var = $var->${key}();
}
else if (is_array($var) && isset($var[$key])) {
$var = $var[$key];
}
else if (is_array($var) && isset($var[$vkeys[0]]) && is_object($var[$vkeys[0]]) && method_exists($var[$vkeys[0]], $key)) {
$tmp = array();
foreach ($vkeys as $vkey) {
if (is_object($var[$vkey]) && method_exists($var[$vkey], $key)) {
$tmp[] = $var[$vkey]->${key}();
}
}
$var = $tmp;
}
else if (is_array($var) && isset($var[$vkeys[0]]) && isset($var[$vkeys[0]][$key])) {
$tmp = array();
foreach ($vkeys as $vkey) {
if (isset($var[$vkey][$key])) {
$tmp[] = $var[$vkey][$key];
}
}
$var = $tmp;
}
}
}
return $var;
}
// }}}
// {{{ getArray()
/**
* simple method that returns an array of size $size
*
* @param int $size the size of the array to return
* @param int $start the starting index of the array
* @param int $increment the increment
* @access public static
* @return array
*/
function getArray($size, $start = 1, $increment = 1) {
if (is_array($size)) {
$increment = $size[2];
$start = $size[1];
$size = $size[0];
}
$arr = array();
for ($i=0; $i<$size; $i++) {
$arr[] = $start + ($i * $increment);
}
return $arr;
}
// }}}
// {{{ getArrayReverse()
/**
* same as #getArray, but returns elements in reverse order
*
* @param int $size the size of the array to return
* @param int $start the starting index of the array
* @param int $increment the increment
* @access public static
* @return array
*/
function getArrayReverse($size, $start = 1, $increment = 1) {
$arr = SRA_Util::getArray($size, $start, $increment);
rsort($arr);
return $arr;
}
// }}}
// {{{ equal()
/**
* returns TRUE if $attr and $match are equal based on the following criteria:
* 1) if $attr and $match are both the same scalar type and equal, then return TRUE.
* 2) if $attr and $match are both objects with equals methods, then return $attr->equals($match)
* 3) if $attr or $match are objects with a "getPrimaryKey" method, invoke those methods and compare the results, return TRUE if equal
* 4) if $attr is an array, and $match is not, then check 1-3 for each element in $attr, return TRUE if any matches are found
* 5) if $attr is an array and $match is an array, then check 4 for each element of $match and return TRUE if all return TRUE
* 6) if $attr and $match are both booleans (as determined by SRA_Util::isBoolean) and equal (as determined by SRA_Util::convertBoolean), then return TRUE
*
* @param mixed $attr the attribute value
* @param mixed $match the value to match
* @access public static
* @return boolean
*/
function equal(& $attr, & $match) {
// evaluate single characters
if (is_scalar($attr) && is_scalar($match) && preg_match('/^[a-zA-Z]$/', $attr) && preg_match('/^[a-zA-Z]$/', $match)) {
return $attr === $match;
}
// evalutate booleans
if (is_scalar($attr) && SRA_Util::isBoolean($attr) && is_scalar($match) && SRA_Util::isBoolean($match)) {
return SRA_Util::convertBoolean($attr) === SRA_Util::convertBoolean($match);
}
// evaluate dates
if (SRA_GregorianDate::isValid($attr) || SRA_GregorianDate::isValid($match)) {
return SRA_GregorianDate::isValid($attr) ? $attr->equals($match) : $match->equals($attr);
}
if (!isset($attr) && !isset($match)) {
return TRUE;
}
if (is_scalar($attr) && is_scalar($match) && (($attr == $match && strlen($attr) == strlen($match)))) {
return TRUE;
}
if (is_object($attr) && is_object($match) && method_exists($attr, 'equals') && method_exists($match, 'equals')) {
return $attr->equals($match);
}
$apk = FALSE;
if (is_object($attr) && method_exists($attr, 'getPrimaryKey')) {
$apk = $attr->getPrimaryKey();
}
$mpk = FALSE;
if (is_object($match) && method_exists($match, 'getPrimaryKey')) {
$mpk = $match->getPrimaryKey();
}
if (($apk || $mpk) && ($apk == $mpk || (is_scalar($match) && $apk == $match) || (is_scalar($attr) && $attr == $mpk))) {
return TRUE;
}
if (is_array($attr) && is_array($match)) {
$keys = array_keys($attr);
$mkeys = array_keys($match);
foreach ($mkeys as $mkey) {
$found = FALSE;
foreach ($keys as $key) {
if (SRA_Util::equal($attr[$key], $match[$mkey])) {
$found = TRUE;
break;
}
}
if (!$found) {
break;
}
}
}
else if (is_array($attr)) {
$keys = array_keys($attr);
foreach ($keys as $key) {
if (SRA_Util::equal($attr[$key], $match)) {
return TRUE;
}
}
}
return FALSE;
}
// }}}
// {{{ getNewMatrix()
/**
* returns a new instance of a SRA_Matrix object
*
* @access public static
* @return SRA_Matrix
*/
function getNewMatrix() {
include_once('SRA_Matrix.php');
return new SRA_Matrix();
}
// }}}
// {{{ invokeMethod()
/**
* invoked a method on an object if it exists and returns the value of that
* method call. returns $obj if $obj is not an object or the $method does not
* exist
*
* @param Object $obj the object to invoke the method on
* @param string $method the name of the method
* @param string $param1 the first parameter (optional)
* @param string $param2 the second parameter (optional)
* @param string $param3 the third parameter (optional)
* @access public static
* @return mixed
*/
function &invokeMethod(& $obj, $method, $param1 = FALSE, $param2 = FALSE, $param3 = FALSE) {
if (is_object($obj) && method_exists($obj, $method)) {
if ($param3) {
return $obj->${method}($param1, $param2, $param3);
}
else if ($param2) {
return $obj->${method}($param1, $param2);
}
else if ($param1) {
return $obj->${method}($param1);
}
else {
return $obj->${method}();
}
}
return $obj;
}
// }}}
// {{{ methodExists()
/**
* returns TRUE if $obj is an object and has a method $method
*
* @param mixed $obj the object to check
* @param string $method the name of the method
* @access public static
* @return boolean
*/
function methodExists(& $obj, $method) {
return is_object($obj) && method_exists($obj, $method);
}
// }}}
// {{{ mergeObject()
/**
* recursively merges the attributes of 2 objects. only those attrs that exist
* in $merge and not in $obj (or are not set) will be merged unless $overwrite
* is TRUE
*
* @param Object $obj the object to merge into
* @param Object $merge the object to merge with
* @param boolean $overwrite whether or not to overwrite attributes in $obj
* that exist in $merge
* @access public static
* @return void
*/
function mergeObject(& $obj, & $merge, $overwrite=FALSE) {
$attrs = get_object_vars($merge);
foreach ($attrs as $attr => $val) {
if (!isset($obj->$attr) || $overwrite) {
$obj->$attr = $val;
}
else if (is_object($merge->$attr) && is_object($obj->$attr)) {
SRA_Util::mergeObject($obj->$attr, $val, $overwrite);
}
else if (is_array($merge->$attr) && is_array($obj->$attr)) {
SRA_Util::mergeArray($obj->$attr, $val, $overwrite);
}
}
}
// }}}
// {{{ mergeArray()
/**
* recursively merges the 2 arrays. only those attrs that exist in $arr2
* and not in $arr1 (or are not set) will be merged
*
* @param array $arr1 the array to merge into
* @param array $arr2 the array to merge with
* @param boolean $overwrite whether or not to overwrite elements in $obj
* that exist in $merge
* @access public static
* @return void
*/
function mergeArray(& $arr1, & $arr2, $overwrite=FALSE) {
$keys = array_keys($arr2);
foreach ($keys as $key) {
if (!isset($arr1[$key]) || $overwrite) {
$arr1[$key] = $arr2[$key];
}
else if (is_object($arr1[$key]) && is_object($arr2[$key])) {
SRA_Util::mergeObject($arr1[$key], $arr2[$key], $overwrite);
}
else if (is_array($arr1[$key]) && is_array($arr2[$key])) {
SRA_Util::mergeArray($arr1[$key], $arr2[$key], $overwrite);
}
}
}
// }}}
// {{{ isObject()
/**
* used to validate an object is actually an object and optionally of a
* specific type
*
* @param Object $obj the object to validate
* @param string $the type to validate. optional, if not specified the $obj
* will simply be validated as an object
* @access public static
* @return void
*/
function isObject(& $obj, $type=FALSE) {
if (is_object($obj)) {
if (!$type || strtolower(get_class($obj)) == strtolower($type)) {
return TRUE;
}
}
return FALSE;
}
// }}}
// {{{ isNumericArray()
/**
* returns true if $arr is an array with a numeric incrementing index starting
* at 0
* @param array $arr the array to check
* @access public static
* @return boolean
*/
function isNumericArray(& $arr) {
if (is_array($arr)) {
$keys = array_keys($arr);
$start = 0;
foreach($keys as $key) {
if ($start !== $key) { return FALSE; }
$start++;
}
return TRUE;
}
return FALSE;
}
// }}}
// {{{ substituteParams
/**
* substitutes params in $str with their values in $params where the values
* are embedded using the format "${param name}"
*
* @param string $str the string to parse
* @param array $params the param values to substitute
* @access public
* @return string
*/
function substituteParams($str, $params) {
if (is_array($params)) {
$keys = array_keys($params);
foreach($keys as $key) {
$str = str_replace('${' . $key . '}', $params[$key], $str);
}
}
return $str;
}
// }}}
// {{{ getGlobal
/**
* returns the value of a global variable
*
* @param string $name the name of the global variable to return
* @access public
* @return string
*/
function &getGlobal($name) {
global ${$name};
return ${$name};
}
// }}}
// {{{ setGlobal
/**
* sets a global variable
* @param string $name the name of the global variable to set
* @param mixed $val the value to set (passed and set by reference)
* @access public
* @return void
*/
function &setGlobal($name, $val) {
global ${$name};
${$name} = $val;
}
// }}}
// {{{ cliPrompt
/**
* prompts the user for an input value from the command line and returns that
* value
* @param string $question the question to ask when prompting
* @param boolean $required whether or not a response is required. if not
* required and the user does not provide a value, NULL will be returned
* @param array $options an optional array of valid response values. if
* specified, the user, will be continually asked $question until they provide
* one of these values
* @access public
* @return string
*/
function cliPrompt($question, $required=TRUE, $options=NULL) {
if ($options) {
foreach(array_keys($options) as $key) {
$options[$key] = strtolower($options[$key]);
}
}
$_readline = function_exists('readline');
if (!$_readline) { $stdin = fopen('php://stdin', 'r'); }
echo "\n";
while(TRUE) {
if ($_readline) {
$response = readline($question . ' ');
}
else {
echo $question . ' ';
$response = strtolower(trim(fgets($stdin, 1000)));
}
if (($response && (!$options || in_array(strtolower(trim($response)), $options))) || !$required) { break; }
}
if (!$_readline) { fclose($stdin); }
return $response ? $response : NULL;
}
// }}}
// {{{ suCmds
/**
* uses expect (http://expect.nist.gov) to login as another user and execute
* the commands specified by $cmds. returns a hash indexed by the $cmds where
* the value is the result of executing those commands if the login was
* successful (returns TRUE if $cmds is not specified). otherwise, returns 0
* if expect is not installed, -1 for invalid user, -2 for invalid password
* @param string $user the name of the user to login as
* @param string $pswd the user's password
* @param mixed $cmds the commands to execute. if not specified, TRUE will be
* returned if the login is successful. alternatively, this parameter can be
* a single string command in which case the return value will be a string
* representing the results of invoking that command instead of a hash indexed
* by command
* @param hash $callbacks an optional array of callback methods to execute on
* the return values for $cmds. this value should be indexed by $cmd. when
* specified the return values will be substituted with the results of
* invoking those callback methods. each value specified can either be a
* full function call with the key ${results} which will be substituted with
* the command result value or just the function name in which case the
* function will be invoked with the command return value as the first
* parameter
* @param boolean $skipSuIfEqual when TRUE and SRA_Util::getCurrentUser() is
* the same as $user, su will not be performed
* @param boolean $asynchronous when TRUE, the su and command execution will
* be invoked asynchronously using a separate process and the return value
* will always be NULL (the results of the execution will be unknown)
* @access public
* @return mixed
*/
function suCmds($user, $pswd, $cmds=NULL, $callbacks=NULL, $skipSuIfEqual=FALSE, $asynchronous=FALSE) {
if ($cmds && !is_array($cmds)) {
$cmds = array($cmds);
$returnFirst = TRUE;
}
// create expect su script if it does not already exist
$skipSu = $skipSuIfEqual && $user == SRA_Util::getCurrentUser();
// make sure expect is installed
if (!$skipSu && !($expect = SRA_File::findInPath('expect'))) {
return 0;
}
$script = SRA_Controller::getSysTmpDir() . '/' . SRA_UTIL_SU_CMDS_SCRIPT;
if (!$skipSu && !file_exists($script)) {
$fp = fopen($script, 'w');
fwrite($fp, "#!${expect} -f\n");
fwrite($fp, "set user [lindex \$argv 0]\n");
fwrite($fp, "set password [lindex \$argv 1]\n");
fwrite($fp, "spawn su - \$user\n");
fwrite($fp, "expect {\n");
fwrite($fp, SRA_UTIL_SU_PASSWORD . ' {' . "\n");
fwrite($fp, 'send "$password\r"' . "\n");
fwrite($fp, 'for {set i 2} {$i < $argc} {incr i} {' . "\n");
fwrite($fp, ' set cmd [lindex $argv $i]' . "\n");
fwrite($fp, ' send "$cmd\r"' . "\n");
fwrite($fp, "}\n");
fwrite($fp, 'send "exit 1\r"' . "\n");
fwrite($fp, 'expect eof }}');
fclose($fp);
chmod($script, 0755);
}
$results = array();
if ($skipSu) {
if ($cmds) {
foreach($cmds as $tmp) {
ob_start();
passthru($tmp . ($asynchronous ? ' > /dev/null &' : ''));
$results[$tmp] = trim(ob_get_contents());
ob_end_clean();
}
}
if ($asynchronous) { return NULL; }
}
else {
$cmd = "$script $user $pswd";
foreach($cmds as $tmp) {
if (trim($tmp)) {
$cmd .= ' ' . (strpos($tmp, ' ') ? '"' . str_replace('"', '\"', $tmp) . '"' : $tmp);
}
}
ob_start();
$cmd = $cmd . ($asynchronous ? ' > /dev/null &' : '');
passthru($cmd);
$buffer = ob_get_contents();
ob_end_clean();
if ($asynchronous) { return NULL; }
if ($cmds && is_array($cmds)) {
$lines = explode("\n", $buffer);
foreach($cmds as $idx => $cmd) {
$started = FALSE;
foreach($lines as $line) {
if (SRA_Util::endsWith(trim($line), isset($cmds[$idx + 1]) ? $cmds[$idx + 1] : 'exit 1')) { $started = FALSE; }
if ($started) { $results[$cmd] .= ($results[$cmd] ? "\n" : '') . trim($line); }
if (SRA_Util::endsWith(trim($line), $cmd)) {
$results[$cmd] = '';
$started = TRUE;
}
}
}
}
}
if ($callbacks && is_array($callbacks)) {
foreach($callbacks as $cmd => $callback) {
if (isset($results[$cmd])) {
eval('$results[$cmd]=' . (strpos($callback, '(') ? SRA_Util::substituteParams($callback, array('results' => '$results[$cmd]')) : ($callback . '($results[$cmd])')) . ';');
}
}
}
if (!$skipSu) {
foreach(explode('|', SRA_UTIL_SU_CMDS_INVALID_USER) as $tmp) {
if (strpos($buffer, trim($tmp)) !== FALSE) {
return -1;
}
}
foreach(explode('|', SRA_UTIL_SU_CMDS_INVALID_PSWD) as $tmp) {
if (strpos($buffer, trim($tmp)) !== FALSE) {
return -2;
}
}
}
return $cmds ? ($returnFirst ? $results[$cmds[0]] : $results) : TRUE;
}
// }}}
// {{{ passwd
/**
* uses expect (http://expect.nist.gov) to change the current running user's
* password. alternatively, if the current running user is root, $user may be
* specified identifying the name of another user to change the password for.
* returns TRUE on success, FALSE otherwise
* @param string $pswd the new password
* @param string $curPswd the existing password. required, unless being
* invoked by the root user
* @param string $user the username to change the password for. if not
* specified, the current user's password will be changed
* @param string $output an optional reference variable that will be set with
* the results of the passwd execution
* @access public
* @return boolean
*/
function passwd($pswd, $curPswd=NULL, $user=NULL, &$output) {
$ret = FALSE;
if (($curPswd || SRA_Util::getCurrentUser() == SRA_UTIL_ROOT) && (!$user || SRA_Util::getCurrentUser() == SRA_UTIL_ROOT) && ($expect = SRA_File::findInPath('expect'))) {
$fp = fopen($script = SRA_File::createRandomFile(NULL, '', '', '', TRUE), 'w');
fwrite($fp, "#!${expect} -f\n");
fwrite($fp, 'spawn passwd' . ($user ? ' ' . $user : '') . "\n");
if (SRA_Util::getCurrentUser() != SRA_UTIL_ROOT) {
fwrite($fp, 'expect "current"' . "\n");
fwrite($fp, 'send "' . $curPswd . '\r"' . "\n");
}
fwrite($fp, 'expect "ew" {' . "\n");
fwrite($fp, ' send "' . $pswd . '\r"' . "\n");
fwrite($fp, ' expect {' . "\n");
fwrite($fp, ' "' . SRA_UTIL_SU_PSWD_RETYPE. '" {' . "\n");
fwrite($fp, ' send "' . $pswd . '\r"' . "\n");
fwrite($fp, ' }' . "\n");
if (SRA_Util::getCurrentUser() != SRA_UTIL_ROOT) {
fwrite($fp, ' "BAD" {' . "\n");
fwrite($fp, ' send \003' . "\n");
fwrite($fp, ' }' . "\n");
}
fwrite($fp, ' }' . "\n");
fwrite($fp, '}' . "\n");
fwrite($fp, "expect eof\n");
fclose($fp);
chmod($script, 0755);
ob_start();
passthru($script);
$output = ob_get_contents();
ob_end_clean();
$ret = strpos($output, SRA_UTIL_SU_PSWD_RETYPE) !== FALSE ? TRUE : FALSE;
}
return $ret;
}
// }}}
// {{{ suPasswd
/**
* uses expect (http://expect.nist.gov) to change a system user's password.
* return TRUE on success, FALSE otherwise
* @param string $user the name of the user to change the password for
* @param string $pswd the user's current password (or root's password if
* $root is TRUE)
* @param string $newPswd the new password to set
* @param boolean $root whether or not to use the root user to change the
* password. when TRUE, $pswd should be the root user password and not the
* password of $user
* @param string $output an optional reference variable that will be set with
* the results of the passwd execution
* @access public
* @return boolean
*/
function suPasswd($user, $pswd, $newPswd, $root=FALSE, &$output) {
$ret = FALSE;
if ($user && $pswd && $newPswd && $pswd != $newPswd && SRA_Util::suCmds($root ? 'root' : $user, $pswd) === TRUE) {
$expect = SRA_File::findInPath('expect');
$fp = fopen($script = SRA_File::createRandomFile(NULL, '', '', '', TRUE), 'w');
fwrite($fp, "#!${expect} -f\n");
fwrite($fp, 'spawn su ' . ($root ? 'root' : $user) . "\n");
fwrite($fp, 'expect ' . SRA_UTIL_SU_PASSWORD . "\n");
fwrite($fp, 'send "' . $pswd . '\r"' . "\n");
fwrite($fp, 'send "passwd' . ($root ? ' ' . $user : '') . '\r"' . "\n");
if (!$root) {
fwrite($fp, 'expect ' . SRA_UTIL_SU_PASSWORD . "\n");
fwrite($fp, 'send "' . $pswd . '\r"' . "\n");
}
fwrite($fp, "expect New\n");
fwrite($fp, 'send "' . $newPswd . '\r"' . "\n");
fwrite($fp, "expect {\n");
if (!$root) {
fwrite($fp, ' "' . SRA_UTIL_SU_PSWD_BAD . '" { ' . "\n");
fwrite($fp, ' send \003' . "\n");
fwrite($fp, ' exit' . "\n");
fwrite($fp, " }\n");
}
fwrite($fp, ' "' . SRA_UTIL_SU_PSWD_RETYPE . '" { send "' . $newPswd . '\r"' . " }\n");
fwrite($fp, "}\n");
fwrite($fp, 'send "exit\r"' . "\n");
fwrite($fp, 'expect eof');
fclose($fp);
chmod($script, 0755);
ob_start();
passthru($script);
$output = ob_get_contents();
ob_end_clean();
$ret = strpos($output, SRA_UTIL_SU_PSWD_RETYPE) !== FALSE ? TRUE : FALSE;
}
return $ret;
}
// }}}
// {{{ propertiesStringToHash
/**
* this method converts a properties string into a hash. a properties string
* is a string containing key/value pairs where each pair is separated by a
* newline character and the key/value pair is separated by a equals sign.
* for example, the string:
* test1=test 1 string
* test2=test 2 string
* would result in this method returns the hash:
* array('test1' => 'test 1 string', 'test2' => 'test 2 string')
* comments can be delimited using a preceding #
* @param string $str the properties string to parses
* @return hash
*/
function propertiesStringToHash($str) {
$hash = array();
$lines = explode("\n", $str);
foreach($lines as $line) {
if (substr($line, 0, 1) != '#' && strstr($line, '=')) {
$pair = explode('=', $line);
$pkey = trim($pair[0]);
$pvalue = substr(strstr($line, '='), 1);
// check for line breaks
$pvalue = str_replace("\\\\n", "[#BREAK#]", $pvalue);
$pvalue = str_replace("\\n", "\n", $pvalue);
$pvalue = str_replace("[#BREAK#]", "\\n", $pvalue);
// Check for embedded php code
if (strstr($pvalue, "php::")) {
$pvalue = preg_replace_callback("'php::(.*?)::php'si", "codeToString", $pvalue);
}
$hash[$pkey] = $pvalue;
}
}
return $hash;
}
// }}}
// {{{ isAlphaNumeric
/**
* returns TRUE if $str is an alphanumeric string
* @param string $str the string to check
* @return boolean
*/
function isAlphaNumeric($str) {
return ereg('[^A-Za-z0-9]', $str) ? FALSE : TRUE;
}
// }}}
// {{{ trimLeadingZeros
/**
* trims any leading zeros from $str. if $str consists of only 0s, 0 will be
* returned
* @param string $str the string to trim the leading zeros from
* @access public
* @return string
*/
function trimLeadingZeros($str) {
$trimmed = '';
$started = FALSE;
for($i=0; $i<strlen($str); $i++) {
$char = substr($str, $i, 1);
if ($char !== '0') { $started = TRUE; }
$trimmed .= $started ? $char : '';
}
return strlen($trimmed) ? $trimmed : '0';
}
// }}}
// {{{ trimTrailingZeros
/**
* trims any trailing zeros from $str. if $str consists of only 0s, 0 will be
* returned
* @param string $str the string to trim the leading zeros from
* @access public
* @return string
*/
function trimTrailingZeros($str) {
$trimmed = '';
$started = FALSE;
for($i=strlen($str)-1; $i>=0; $i--) {
$char = substr($str, $i, 1);
if ($char !== '0') { $started = TRUE; }
if ($started) { $trimmed = $char . $trimmed; }
}
return strlen($trimmed) ? $trimmed : '0';
}
// }}}
// {{{ normalizeDataUnit
/**
* this method is used to normalize a data unit. normalization involves first
* determining the unit size by parsing $data for a standard unit symbol or
* name and then applying the correct multiplier to convert the numeric value
* in $data to the new $unit of measure. return return value will either be
* the numeric representation of $data in $unit or the numeric value followed
* by the specified $suffix (if $suffix is specified). if $data cannot be
* parsed its numeric value will be returned. the following unit labels are
* recognized ($data can be parsed with or without spaces between the numeric
* value and the unit label) - note labels are case sensative except for the
* non abbreviated value (i.e. both 'bit' and 'BIT' are recognized):
* UNIT LABELS
* bit: b bs bS bps bpS b/s b/S bit bit/s
* byte: B Bs BS Bps BpS B/s B/S byte byte/s
* kilobit: Kb kb Kbs kbs KbS kbS Kbps KbpS kbps kbpS Kb/s Kb/S kb/s kb/S kilobit[s] kbit[s] kbit/s kilobit/s kilo bit[s]
* kilobyte: KB kB KBs kBs KBS kBS KBps KBpS kBps kBpS KB/s KB/S kB/s kB/S kilobyte[s] kbyte[s] kbyte/s kilobyte/s kilo byte[s]
* megabit: Mb mb Mbs mbs MbS mbS Mbps MbpS mbps mbpS Mb/s Mb/S mb/s mb/S megabit[s] mbit[s] mbit/s megabit/s mega bit[s]
* megabyte: MB mB MBs mBs MBS mBS MBps MBpS mBps mBpS MB/s MB/S mB/s mB/S megabyte[s] mbyte[s] mbyte/s megabyte/s mega byte[s]
* gigabit: Gb gb Gbs gbs GbS gbS Gbps GbpS gbps gbpS Gb/s Gb/S gb/s gb/S gigabit[s] gbit[s] gbit/s gigabit/s giga bit[s]
* gigabyte: GB gB GBs gBs GBS gBS GBps GBpS gBps gBpS GB/s GB/S gB/s gB/S gigabyte[s] gbyte[s] gbyte/s gigabyte/s giga byte[s]
* terabit: Tb tb Tbs tbs TbS tbS Tbps TbpS tbps tbpS Tb/s Tb/S tb/s tb/S terabit[s] tbit[s] tbit/s terabit/s tera bit[s]
* terabyte: TB tB TBs tBs TBS tBS TBps TBpS tBps tBpS TB/s TB/S tB/s tB/S terabyte[s] tbyte[s] tbyte/s terabyte/s tera byte[s]
* NOTE: this method is not localized - it interprets and outputs only english
* strings
* @param mixed $data the data unit size and unit size label to normalize
* represents as a string (i.e. '567Mb'), or a hash with the following 2 keys:
* 'value': the value to convert, 'unit' the current unit identifier
* @param int $unit the identifier of the unit that $data should be converted
* to. this value must correspond with one of the SRA_UTIL_DATA_UNIT_*
* constants (see the constant declarations at the top of this file). if not
* specified, the corresponding unit (bits or bytes depending on the unit
* label in $data) that will represent $data in the smallest whole number will
* be used
* @param mixed $suffix if the return value should include the unit size
* label suffix this attribute may be used to specify which label to use. the
* options are 1 for the same abbreviation in the new $unit, 2 for the default
* unit size abbreviation or 3 for the default unit size name or a custom
* suffix string. NOTE: if $suffix is 2 or 3 and the $data unit identifier
* includes the per second identifier, the new suffix will also include this
* identifier (the default labels are the first 4 labels in the
* SRA_UTIL_DATA_UNIT_*_LABELS constants)
* @param boolean $base2 whether or not to use base 2 or base 10 conversions
* i.e. is a kilobyte 2^10 or 1024 bytes or 10^3 or 1000 bytes. the correct
* conversion is base 10 according to the International Electrotechnical
* Commission (IEC), the International Committee for Weights and Measures
* (CIPM) and the Institute of Electrical and Electronics Engineers (IEEE)
* for more information see: http://physics.nist.gov/cuu/Units/binary.html
* @param int $decimals the max # of decimals to include in the normalized
* value
* @access public
* @return mixed
*/
function normalizeDataUnit($data, $unit=NULL, $suffix=1, $decimals=2, $base2=FALSE) {
static $_cachedNormalizedDataUnits;
if (!isset($_cachedNormalizedDataUnits)) $_cachedNormalizedDataUnits = array();
if ($unit && strpos($unit, '/') && count($tmp = explode('/', $unit)) == 2) {
$unit = $tmp[0];
}
if (is_array($data)) {
$normalized = $data['value']*1;
$dataUnit = $data['unit'];
}
else {
$normalized = $data*1;
}
// checked for cached value
$ckey = $normalized . '_' . $dataUnit . '_' . $unit . '_' . $suffix . '_' . $decimals . '_' . $base2;
if (isset($_cachedNormalizedDataUnits[$ckey])) {
return $_cachedNormalizedDataUnits[$ckey];
}
$labelsHash = array(SRA_UTIL_DATA_UNIT_TERABYTE => SRA_UTIL_DATA_UNIT_TERABYTE_LABELS,
SRA_UTIL_DATA_UNIT_TERABIT => SRA_UTIL_DATA_UNIT_TERABIT_LABELS,
SRA_UTIL_DATA_UNIT_GIGABYTE => SRA_UTIL_DATA_UNIT_GIGABYTE_LABELS,
SRA_UTIL_DATA_UNIT_GIGABIT => SRA_UTIL_DATA_UNIT_GIGABIT_LABELS,
SRA_UTIL_DATA_UNIT_MEGABYTE => SRA_UTIL_DATA_UNIT_MEGABYTE_LABELS,
SRA_UTIL_DATA_UNIT_MEGABIT => SRA_UTIL_DATA_UNIT_MEGABIT_LABELS,
SRA_UTIL_DATA_UNIT_KILOBYTE => SRA_UTIL_DATA_UNIT_KILOBYTE_LABELS,
SRA_UTIL_DATA_UNIT_KILOBIT => SRA_UTIL_DATA_UNIT_KILOBIT_LABELS,
SRA_UTIL_DATA_UNIT_BYTE => SRA_UTIL_DATA_UNIT_BYTE_LABELS,
SRA_UTIL_DATA_UNIT_BIT => SRA_UTIL_DATA_UNIT_BIT_LABELS);
if ($data && ($dataUnit || !is_numeric($data)) && (($unit && $labelsHash[$unit]) || !$unit)) {
$ldata = strtolower($dataUnit ? $dataUnit : $data);
foreach ($labelsHash as $evalUnit => $labels) {
$labels = array_reverse(explode(',', $labels));
foreach ($labels as $idx => $label) {
$lower = substr($label, 0, 1) == ':' ? TRUE : FALSE;
if ($lower) { $label = strtolower(substr($label, 1)); }
if (trim($label) && (!$foundLabel || strlen($label) > strlen($foundLabel)) && preg_match('/' . str_replace('/', '\/', $label) . '/', $lower ? $ldata : ($dataUnit ? $dataUnit : $data))) {
$useUpper = strpos($dataUnit ? $dataUnit : $data, $label) === FALSE ? TRUE : FALSE;
$perS = (!$lower && SRA_Util::endsWith(strtolower($label), 's')) || ($lower && SRA_Util::endsWith(strtolower($label), '/s'));
$includeSpace = preg_match('/' . str_replace('/', '\/', ' ' . $label) . '/', $lower ? $ldata : ($dataUnit ? $dataUnit : $data));
$useLower = $lower;
$useIdx = $idx;
$foundLabel = $label;
$dataUnit = $evalUnit;
$useBits = $dataUnit == SRA_UTIL_DATA_UNIT_TERABIT || $dataUnit == SRA_UTIL_DATA_UNIT_GIGABIT || $dataUnit == SRA_UTIL_DATA_UNIT_MEGABIT || $dataUnit == SRA_UTIL_DATA_UNIT_KILOBIT || $dataUnit == SRA_UTIL_DATA_UNIT_BIT;
}
}
}
if ($dataUnit) {
switch($dataUnit) {
case SRA_UTIL_DATA_UNIT_BIT:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 8796093022208 : 8000000000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 1099511627776 : 1000000000000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 8589934592 : 8000000000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '/', 'val' => $base2 ? 8388608 : 8000000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '/', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '/', 'val' => 8),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => 1));
break;
case SRA_UTIL_DATA_UNIT_BYTE:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 1099511627776 : 1000000000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 137438953472 : 125000000000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 134217728 : 125000000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '/', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '/', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => 8));
break;
case SRA_UTIL_DATA_UNIT_KILOBIT:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 8589934592 : 8000000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 8388608 : 8000000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '/', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '/', 'val' => 8),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 1024 : 1000));
break;
case SRA_UTIL_DATA_UNIT_KILOBYTE:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 134217728 : 125000000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '/', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => 8),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 8192 : 8000));
break;
case SRA_UTIL_DATA_UNIT_MEGABIT:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 8388608 : 8000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '/', 'val' => 8),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000));
break;
case SRA_UTIL_DATA_UNIT_MEGABYTE:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '/', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => 8),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 8388608 : 8000000));
break;
case SRA_UTIL_DATA_UNIT_GIGABIT:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '/', 'val' => 8),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '*', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 134217728 : 125000000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 1073741824 : 1000000000));
break;
case SRA_UTIL_DATA_UNIT_GIGABYTE:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '/', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '*', 'val' => 8),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 8388608 : 8000000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 8589934592 : 8000000000));
break;
case SRA_UTIL_DATA_UNIT_TERABIT:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '/', 'val' => 8),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '*', 'val' => $base2 ? 128 : 125),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '*', 'val' => $base2 ? 131072 : 125000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 134217728 : 125000000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 137438953472 : 125000000000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 1099511627776 : 1000000000000));
break;
case SRA_UTIL_DATA_UNIT_TERABYTE:
$conversions = array(SRA_UTIL_DATA_UNIT_TERABYTE => array('op' => '*', 'val' => 1),
SRA_UTIL_DATA_UNIT_TERABIT => array('op' => '*', 'val' => 8),
SRA_UTIL_DATA_UNIT_GIGABYTE => array('op' => '*', 'val' => $base2 ? 1024 : 1000),
SRA_UTIL_DATA_UNIT_GIGABIT => array('op' => '*', 'val' => $base2 ? 8192 : 8000),
SRA_UTIL_DATA_UNIT_MEGABYTE => array('op' => '*', 'val' => $base2 ? 1048576 : 1000000),
SRA_UTIL_DATA_UNIT_MEGABIT => array('op' => '*', 'val' => $base2 ? 8388608 : 8000000),
SRA_UTIL_DATA_UNIT_KILOBYTE => array('op' => '*', 'val' => $base2 ? 1073741824 : 1000000000),
SRA_UTIL_DATA_UNIT_KILOBIT => array('op' => '*', 'val' => $base2 ? 8589934592 : 8000000000),
SRA_UTIL_DATA_UNIT_BYTE => array('op' => '*', 'val' => $base2 ? 1099511627776 : 1000000000000),
SRA_UTIL_DATA_UNIT_BIT => array('op' => '*', 'val' => $base2 ? 8796093022208 : 8000000000000));
break;
}
$keys = array_keys($conversions);
if (!$unit) {
for($i=0; $i<count($keys); $i++) {
if (($useBits && ($keys[$i] == SRA_UTIL_DATA_UNIT_TERABIT || $keys[$i] == SRA_UTIL_DATA_UNIT_GIGABIT || $keys[$i] == SRA_UTIL_DATA_UNIT_MEGABIT || $keys[$i] == SRA_UTIL_DATA_UNIT_KILOBIT || $keys[$i] == SRA_UTIL_DATA_UNIT_BIT)) || (!$useBits && ($keys[$i] == SRA_UTIL_DATA_UNIT_TERABYTE || $keys[$i] == SRA_UTIL_DATA_UNIT_GIGABYTE || $keys[$i] == SRA_UTIL_DATA_UNIT_MEGABYTE || $keys[$i] == SRA_UTIL_DATA_UNIT_KILOBYTE || $keys[$i] == SRA_UTIL_DATA_UNIT_BYTE))) {
if ($normalized >= $conversions[$keys[$i]]['val'] && (!$lastUnit || $normalized < $conversions[$lastUnit]['val'])) {
$unit = $keys[$i];
break;
}
$lastUnit = $keys[$i];
}
}
if (!$unit) { $unit = $dataUnit; }
}
if ($conversions[$unit]) {
eval('$normalized' . $conversions[$unit]['op'] . '=' . $conversions[$unit]['val'] . ';');
}
}
if ($unit && $labelsHash[$unit]) {
$labels = array_reverse(explode(',', $labelsHash[$unit]));
$suffix = $suffix === 1 || $suffix === 2 || $suffix === 3 ? $labels[$suffix == 1 ? $useIdx : (($suffix == 2 ? 0 : 2) + ($perS ? 1 : 0))] . ($suffix === 3 && !$perS && $normalized > 1 ? 's' : '') : $suffix;
if (SRA_Util::endsWith($suffix, 'ss')) { $suffix = substr($suffix, 0, -1); }
if (substr($suffix, 0, 1) == ':') { $suffix = substr($suffix, 1); }
if ($normalized <= 1 && !$perS && SRA_Util::endsWith($suffix, 's')) { $suffix = substr($suffix, 0, -1); }
if ($normalized > 1 && $useLower && !SRA_Util::endsWith($suffix, 's')) { $suffix .= 's'; }
if ($useLower && $useUpper) { $suffix = strtoupper(substr($suffix, 0, 1)) . substr($suffix, 1); }
}
}
if (strpos($normalized, '.') !== FALSE) { $normalized = SRA_Util::trimTrailingZeros(round($normalized, $decimals))*1; }
$val = $normalized . (!$suffix || $suffix === 1 || $suffix === 2 || $suffix === 3 ? '' : ($includeSpace ? ' ' : '') . $suffix);
$_cachedNormalizedDataUnits[$ckey] = $val;
return $val;
}
// }}}
// {{{ normalizeMeasurement
/**
* this method is used to normalize a measurement. normalization involves first
* determining the unit size by parsing $data for a standard unit symbol or
* name and then applying the correct multiplier to convert the numeric value
* in $data to the new $unit of measure. return return value will either be
* the numeric representation of $data in $unit or the numeric value followed
* by the specified $suffix (if $suffix is specified). if $data cannot be
* parsed its numeric value will be returned. the following unit labels are
* recognized ($data can be parsed with or without spaces between the numeric
* value and the unit label) - labels are not case sensitive. conversion cannot
* occur between classes of measurement for obvious reasons.
* UNIT METRIC? LABELS
* LENGTH MEASUREMENTS
* Centimeter: Y centimeter(s) cm cms
* Foot: N foot feet ft fts
* Inch: N inch(es) in ins
* Kilometer: Y kilometer(s) km kms
* Meter: Y meter(s) m ms
* Mile: N mile(s) mi mis
* Yard: N yard(s) yd yds
*
* WEIGHT MEASUREMENTS
* Gram: Y gram(s) gm gms
* Kilogram: Y kilogram(s) kg kgs
* Ounce: N ounce(s) oz ozs
* Pound: N pound(s) lb lbs
* @param mixed $data the data unit size and unit size label to normalize
* represents as a string (i.e. '516 LBS'), or a hash with the following 2/3 keys:
* 'value': the value to convert, 'unit' the current unit identifier, and
* 'multiplier' (optional) - a multiplier to apply to 'value'
* @param int $unit the identifier of the unit that $data should be converted
* to. this value must correspond with one of the SRA_UTIL_MEASUREMENT_*
* constants (see the constant declarations at the top of this file). if not
* specified, the corresponding unit that will represent $data in the smallest
* whole number will be used
* @param mixed $suffix if the return value should include the unit size
* label suffix this attribute may be used to specify which label to use. the
* options are 1 for the same abbreviation in the new $unit, 2 for the unit
* abbreviation or 3 for the unit name
* @param int $decimals the max # of decimals to include in the normalized
* value
* @param SRA_Locale $locale by default if $unit is not specified, $data will
* be normalized using the smallest unit of measure in the same measurement
* systems as specified in $data (i.e. 1000 meters will be converted to 1 kilometer
* NOT 0.62 miles). if you want to change this behavior, you may specify this
* locale parameter and if $locale uses metric measurements, $data will be
* normalized to the measurement system used by that locale
* @access public
* @return mixed
*/
function normalizeMeasurement($data, $unit=NULL, $suffix=1, $decimals=2, $locale=NULL) {
if (is_array($data)) {
$normalized = $data['value']*1;
$dataUnit = isset($data['unit']) ? $data['unit'] : NULL;
if (isset($data['multiplier']) && is_numeric($data['multiplier']) && $data['multiplier'] > 0) {
$normalized *= $data['multiplier'];
}
$data = $data['value'];
$includeSpace = TRUE;
}
else {
$normalized = $data*1;
}
$labelsHash = array(SRA_UTIL_MEASUREMENT_CENTIMETER => ':cm,:cms,:centimeter,:centimeters',
SRA_UTIL_MEASUREMENT_FOOT => ':ft,:fts,:foot,:feet',
SRA_UTIL_MEASUREMENT_INCH => ':in,:ins,:inch,:inches',
SRA_UTIL_MEASUREMENT_KILOMETER => ':km,:kms,:kilometer,:kilometers',
SRA_UTIL_MEASUREMENT_METER => ':m,:ms,:meter,:meters',
SRA_UTIL_MEASUREMENT_MILE => ':mi,:mis,:mile,:miles',
SRA_UTIL_MEASUREMENT_YARD => ':yd,:yds,:yard,:yards',
SRA_UTIL_MEASUREMENT_GRAM => ':gm,:gms,:gram,:grams',
SRA_UTIL_MEASUREMENT_KILOGRAM => ':kg,:kgs,:kilogram,:kilograms',
SRA_UTIL_MEASUREMENT_OUNCE => ':oz,:ozs,:ounce,:ounces',
SRA_UTIL_MEASUREMENT_POUND => ':lb,:lbs,:pound,:pounds');
if ($data && ($dataUnit || !is_numeric($data)) && (($unit && $labelsHash[$unit]) || !$unit)) {
$ldata = strtolower($dataUnit ? $dataUnit : $data);
foreach ($labelsHash as $evalUnit => $labels) {
$labels = array_reverse(explode(',', $labels));
foreach ($labels as $idx => $label) {
$lower = substr($label, 0, 1) == ':' ? TRUE : FALSE;
if ($lower) { $label = strtolower(substr($label, 1)); }
if (trim($label) && (!$foundLabel || strlen($label) > strlen($foundLabel)) && preg_match('/' . str_replace('/', '\/', $label) . '/', $lower ? $ldata : ($dataUnit ? $dataUnit : $data))) {
$useUpper = strpos($dataUnit ? $dataUnit : $data, $label) === FALSE ? TRUE : FALSE;
$includeSpace = !$includeSpace ? (preg_match('/' . str_replace('/', '\/', ' ' . $label) . '/', $lower ? $ldata : ($dataUnit ? $dataUnit : $data))) : TRUE;
$useLower = $lower;
$useIdx = $idx;
$foundLabel = $label;
$dataUnit = $evalUnit;
$useMetric = SRA_Locale::isValid($locale) ? $locale->isMetric() : $dataUnit == SRA_UTIL_MEASUREMENT_CENTIMETER || $dataUnit == SRA_UTIL_MEASUREMENT_KILOMETER || $dataUnit == SRA_UTIL_MEASUREMENT_METER || $dataUnit == SRA_UTIL_MEASUREMENT_GRAM || $dataUnit == SRA_UTIL_MEASUREMENT_KILOGRAM;
}
}
}
if ($dataUnit) {
switch($dataUnit) {
case SRA_UTIL_MEASUREMENT_FOOT:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 5280),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '/', 'val' => 3280.839895),
SRA_UTIL_MEASUREMENT_METER => array('op' => '/', 'val' => 3.280839895),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '/', 'val' => 3),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 12),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 30.48));
break;
case SRA_UTIL_MEASUREMENT_INCH:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 63360.000000068429),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '/', 'val' => 39370.0787402),
SRA_UTIL_MEASUREMENT_METER => array('op' => '/', 'val' => 39.3700787402),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '/', 'val' => 36),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '/', 'val' => 12),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 2.54));
break;
case SRA_UTIL_MEASUREMENT_KILOMETER:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 1.609344),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_METER => array('op' => '*', 'val' => 1000),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '*', 'val' => 1093.613298),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '*', 'val' => 3280.839895),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 39370.0787402),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 100000));
break;
case SRA_UTIL_MEASUREMENT_METER:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 1609.344),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '/', 'val' => 1000),
SRA_UTIL_MEASUREMENT_METER => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '*', 'val' => 1.093613298),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '*', 'val' => 3.280839895),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 39.3700787402),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 100));
break;
case SRA_UTIL_MEASUREMENT_MILE:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '*', 'val' => 1.609344),
SRA_UTIL_MEASUREMENT_METER => array('op' => '*', 'val' => 1609.344),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '*', 'val' => 1759.999999456512),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '*', 'val' => 5279.99999997888),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 63360.000000068429),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 160934.4));
break;
case SRA_UTIL_MEASUREMENT_YARD:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 1760),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '/', 'val' => 1093.613298),
SRA_UTIL_MEASUREMENT_METER => array('op' => '/', 'val' => 1.093613298),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '*', 'val' => 2.999999999988),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '*', 'val' => 36.00000000003888),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 91.44));
break;
case SRA_UTIL_MEASUREMENT_CENTIMETER:
$conversions = array(SRA_UTIL_MEASUREMENT_MILE => array('op' => '/', 'val' => 160934.4),
SRA_UTIL_MEASUREMENT_KILOMETER => array('op' => '/', 'val' => 100000),
SRA_UTIL_MEASUREMENT_METER => array('op' => '/', 'val' => 100),
SRA_UTIL_MEASUREMENT_YARD => array('op' => '/', 'val' => 91.44),
SRA_UTIL_MEASUREMENT_FOOT => array('op' => '/', 'val' => 30.48),
SRA_UTIL_MEASUREMENT_INCH => array('op' => '/', 'val' => 2.54),
SRA_UTIL_MEASUREMENT_CENTIMETER => array('op' => '*', 'val' => 1));
break;
case SRA_UTIL_MEASUREMENT_GRAM:
$conversions = array(SRA_UTIL_MEASUREMENT_KILOGRAM => array('op' => '/', 'val' => 1000),
SRA_UTIL_MEASUREMENT_POUND => array('op' => '/', 'val' => 453.59237),
SRA_UTIL_MEASUREMENT_OUNCE => array('op' => '/', 'val' => 28.349523125),
SRA_UTIL_MEASUREMENT_GRAM => array('op' => '*', 'val' => 1));
break;
case SRA_UTIL_MEASUREMENT_KILOGRAM:
$conversions = array(SRA_UTIL_MEASUREMENT_KILOGRAM => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_POUND => array('op' => '*', 'val' => 2.204622622),
SRA_UTIL_MEASUREMENT_OUNCE => array('op' => '*', 'val' => 35.2739619),
SRA_UTIL_MEASUREMENT_GRAM => array('op' => '*', 'val' => 1000));
break;
case SRA_UTIL_MEASUREMENT_OUNCE:
$conversions = array(SRA_UTIL_MEASUREMENT_KILOGRAM => array('op' => '/', 'val' => 35.2739619),
SRA_UTIL_MEASUREMENT_POUND => array('op' => '/', 'val' => 16),
SRA_UTIL_MEASUREMENT_OUNCE => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_GRAM => array('op' => '*', 'val' => 28.349523125));
break;
case SRA_UTIL_MEASUREMENT_POUND:
$conversions = array(SRA_UTIL_MEASUREMENT_KILOGRAM => array('op' => '/', 'val' => 2.204622622),
SRA_UTIL_MEASUREMENT_POUND => array('op' => '*', 'val' => 1),
SRA_UTIL_MEASUREMENT_OUNCE => array('op' => '*', 'val' => 15.999999977510703),
SRA_UTIL_MEASUREMENT_GRAM => array('op' => '*', 'val' => 453.59237));
break;
}
$keys = array_keys($conversions);
if (!$unit) {
for($i=0; $i<count($keys); $i++) {
if (($useMetric && ($keys[$i] == SRA_UTIL_MEASUREMENT_KILOMETER || $keys[$i] == SRA_UTIL_MEASUREMENT_METER || $keys[$i] == SRA_UTIL_MEASUREMENT_CENTIMETER || $keys[$i] == SRA_UTIL_MEASUREMENT_GRAM || $keys[$i] == SRA_UTIL_MEASUREMENT_KILOGRAM)) || (!$useMetric && ($keys[$i] == SRA_UTIL_MEASUREMENT_FOOT || $keys[$i] == SRA_UTIL_MEASUREMENT_INCH || $keys[$i] == SRA_UTIL_MEASUREMENT_MILE || $keys[$i] == SRA_UTIL_MEASUREMENT_YARD || $keys[$i] == SRA_UTIL_MEASUREMENT_OUNCE || $keys[$i] == SRA_UTIL_MEASUREMENT_POUND))) {
if ($normalized >= $conversions[$keys[$i]]['val'] && (!$lastUnit || $normalized < $conversions[$lastUnit]['val'])) {
$unit = $keys[$i];
break;
}
$lastUnit = $keys[$i];
}
}
if (!$unit) { $unit = $lastUnit ? $lastUnit : $dataUnit; }
}
if ($conversions[$unit]) {
eval('$normalized' . $conversions[$unit]['op'] . '=' . $conversions[$unit]['val'] . ';');
}
}
if ($unit && $labelsHash[$unit]) {
$labels = array_reverse(explode(',', $labelsHash[$unit]));
$suffix = $suffix === 1 || $suffix === 2 || $suffix === 3 ? $labels[$suffix == 1 ? $useIdx : (($suffix == 2 ? 0 : 2))] . ($suffix === 3 && $normalized > 1 ? 's' : '') : $suffix;
if (SRA_Util::endsWith($suffix, 'ss')) { $suffix = substr($suffix, 0, -1); }
if (substr($suffix, 0, 1) == ':') { $suffix = substr($suffix, 1); }
if ($normalized <= 1 && SRA_Util::endsWith($suffix, 's')) { $suffix = substr($suffix, 0, -1); }
if ($normalized > 1 && $useLower && !SRA_Util::endsWith($suffix, 's')) { $suffix .= 's'; }
if ($useLower && $useUpper) { $suffix = strtoupper(substr($suffix, 0, 1)) . substr($suffix, 1); }
}
}
if (strpos($normalized, '.') !== FALSE) { $normalized = SRA_Util::trimTrailingZeros(round($normalized, $decimals))*1; }
if ($suffix == 'feets') $suffix = 'feet';
if ($suffix == 'feet' && $normalized == 1) $suffix = 'foot';
return $normalized . (!$suffix || $suffix === 1 || $suffix === 2 || $suffix === 3 ? '' : ($includeSpace ? ' ' : '') . $suffix);
}
// }}}
// {{{ parsePhpSource
/**
* this method parses a PHP 4.x source file and utilizes javadoc formatted
* comments to construct a hash of metadata pertaining to that file. this hash
* will contain the following keys (comment values can be imbedded using the
* localizeable format "{$[app resource bundle string]}"):
* constants: array of hashes (indexed by name) with the following keys:
* comment: the constant comment
* name: the name of the constant
* value: the constant value
* [other]: other metadata (metadata value keys are prefixed with @)
* classes: array of hashes (indexed by name) with the following keys:
* comment: the class comment
* extends: the name of another class extended by this class
* name: the class name
* [other]: other metadata (metadata value keys are prefixed with @)
* attrs: array of hashes (indexed by name) with the following keys:
* comment: the attribute comment
* name: the name of the attribute
* value: the attribute value
* [other]: other metadata (metadata value keys are prefixed with @)
* methods: array of hashes (indexed by name) with the following keys:
* comment: the method comment
* name: the name of the method
* params: array of hashes (indexed by name) with the following keys:
* byRef: whether or not this parameter is passed by reference
* comment: the parameter comment
* name: the name of the parameter
* type: the parameter data type
* value: the default parameter value (if applicable)
* returnRef: whether or not this method returns value by reference
* [other]: other metadata (metadata value keys are prefixed with @)
* functions: same as 'methods' documented above, but for non-class
* defined functions
* @param string $file the path to the php source file that should be parsed
* @param boolean $cache whether or not the parse results should be cached
* (cache will be updated if the source file changes)
* @access public
* @return mixed
*/
function &parsePhpSource($file, $cache=TRUE) {
if (!file_exists($file)) {
return NULL;
}
$ckey = 'sra_parse_php_source_' . str_replace('/', '.', $file);
if ($cache) include_once('SRA_Cache.php');
if ($cache && ($modtime = SRA_Cache::cacheIsset($ckey, TRUE)) && $modtime > filemtime($file)) {
return SRA_Cache::getCache($ckey);
}
$resources =& SRA_Controller::getAppResources();
$inClass = NULL;
$metadata = array();
$lines = file($file);
foreach(array_keys($lines) as $i) {
$mergeComment = FALSE;
$mergePoint = NULL;
$lines[$i] = trim($lines[$i]);
$line = $lines[$i];
if ($inComment && (SRA_Util::beginsWith($line, '*/') || SRA_Util::endsWith($line, '*/'))) {
$inComment = FALSE;
if ($api['comment'] && preg_match_all('/\{\$(\w*|.*|_*)\}/', $api['comment'], $m)) {
foreach($m[1] as $key => $val) {
$api['comment'] = str_replace($m[0][$key], $resources->getString($m[1][$key]), $api['comment']);
}
}
}
else if ($inComment) {
$pline = substr($line, strpos($line, '*') + 1);
if (SRA_Util::beginsWith($line, '*')) { $line = $pline . "\n"; }
if (SRA_Util::beginsWith(trim($line), '@') && preg_match('/@[A-Za-z]+/', trim($line), $m)) {
$apiIdx = substr($m[0], 1);
$line = trim(substr(trim($line), strlen($apiIdx) + 1));
if (isset($api[$apiIdx])) {
is_array($api[$apiIdx]) ? $api[$apiIdx][] = '' : $api[$apiIdx] = array($api[$apiIdx], '');
}
}
$val = ((is_array($api[$apiIdx]) && $api[$apiIdx][count($api[$apiIdx]) - 1]) || (!is_array($api[$apiIdx]) && $api[$apiIdx]) ? ' ' : '') . $line;
is_array($api[$apiIdx]) ? $api[$apiIdx][count($api[$apiIdx]) - 1] .= $val : $api[$apiIdx] .= $val;
}
// javadoc comment start
else if (!$inComment && SRA_Util::beginsWith($line, '/**')) {
$cspaces = NULL;
$inComment = TRUE;
$api = array();
$apiIdx = 'comment';
}
// constant
else if (!$inComment && SRA_Util::beginsWith($line, 'define(') && preg_match('/define\([\'\"](.*)[\'\"]\,(.*)\)/', $line, $m) && count($m) == 3) {
$name = trim($m[1]);
if (!isset($metadata['constants'])) { $metadata['constants'] = array(); }
$metadata['constants'][$name] = array('name' => $name, 'value' => trim($m[2]));
$mergeComment = TRUE;
$mergePoint = array('constants', "'$name'");
}
// class
else if (!$inComment && SRA_Util::beginsWith($line, 'class') && (preg_match('/class\s(.*)\sextends\s(.*)\s?/', $line, $m) || preg_match('/class\s(.*)\s/', $line, $m))) {
if (!isset($metadata['classes'])) { $metadata['classes'] = array(); }
$className = trim($m[1]);
$metadata['classes'][$className] = array('name' => $className);
if (isset($m[2]) && trim($m[2])) { $metadata['classes'][$className]['extends'] = trim(str_replace('{', '', $m[2])); }
$mergeComment = TRUE;
$mergePoint = array('classes', "'$className'");
}
// attributes
else if (!$inComment && $className && SRA_Util::beginsWith($line, 'var') && (preg_match('/var (.*)\s?=\s?(.*)\s?;/', $line, $m) || preg_match('/var (.*)\s?;/', $line, $m))) {
if (!isset($metadata['classes'][$className]['attrs'])) { $metadata['classes'][$className]['attrs'] = array(); }
$m[1] = trim(str_replace('$', '', $m[1]));
$metadata['classes'][$className]['attrs'][$m[1]] = array('name' => $m[1]);
if (isset($m[2]) && trim($m[2])) { $metadata['classes'][$className]['attrs'][$m[1]]['value'] = trim($m[2]); }
$mergeComment = TRUE;
$mergePoint = array('classes', "'$className'", 'attrs', "'$m[1]'");
}
// methods/functions
else if (!$inComment && SRA_Util::beginsWith($line, 'function') && preg_match('/function\s(.*)\((.*)\)/', $line, $m)) {
$code = '$metadata' . ($className ? "['classes']['$className']['methods']" : "['functions']");
eval("if (!isset($code)) $code = array();");
$returnRef = SRA_Util::beginsWith(trim($m[1]), '&') ? '1' : '0';
if ($returnRef) $m[1] = trim(substr(trim($m[1]), 1));
$idx = $m[1];
eval($code . '["' . $idx . '"] = array("name" => $m[1], "returnRef" => $returnRef);');
if (trim($m[2])) {
$papi = NULL;
for($n=$i-1; $n>0; $n--) {
if (!$lines[$n]) {
continue;
}
else if ((SRA_Util::beginsWith($lines[$n], '*/') || SRA_Util::endsWith($lines[$n], '*/')) && isset($api['param'])) {
$papi = $api['param'];
unset($api['param']);
}
break;
}
eval($code . '["' . $idx . '"]["params"] = array();');
foreach(explode(',', $m[2]) as $param) {
preg_match('/\$(.*)\s?=\s?(.*)/', $param, $m);
$param = array('name' => trim($m ? '$' . $m[1] : $param));
$param['byRef'] = SRA_Util::beginsWith($param['name'], '&') ? '1' : '0';
if ($param['byRef']) $param['name'] = trim(substr($param['name'], 1));
$param['name'] = str_replace('$', '', $param['name']);
if ($m) { $param['value'] = trim($m[2]); }
if ($papi) {
if (!is_array($papi)) { $papi = array($papi); }
foreach($papi as $p) {
$pieces = explode(' ', $p);
foreach(array_keys($pieces) as $pkey) { if (!trim($pieces[$pkey])) { unset($pieces[$pkey]); } }
$pp = array(); foreach($pieces as $tmp) { $pp[] = SRA_Util::beginsWith(trim($tmp), '$') ? substr($tmp, 1) : $tmp; }
if ($pp[0] == $param['name'] || $pp[1] == $param['name'] || $pp[0] == substr($param['name'], 1) || $pp[1] == substr($param['name'], 1)) {
if ($pp[1] == $param['name'] || $pp[1] == substr($param['name'], 1)) { $param['type'] = trim($pp[0]); }
$param['comment'] = trim(substr($p, strpos($p, substr($param['name'], 1)) + strlen(substr($param['name'], 1))));
if ($param['comment'] && preg_match_all('/\{\$(\w*|.*|_*)\}/', $param['comment'], $m)) {
foreach($m[1] as $key => $val) {
$param['comment'] = str_replace($m[0][$key], $resources->getString($m[1][$key]), $param['comment']);
}
}
}
}
}
eval($code . '["' . $idx . '"]["params"][$param["name"]] = $param;');
}
}
$mergeComment = TRUE;
$mergePoint = $className ? array('classes', "'$className'", 'methods', "'$idx'") : array('functions', "'$idx'");
}
if ($mergeComment) {
for($n=$i-1; $n>0; $n--) {
if (!$lines[$n]) {
continue;
}
else if (SRA_Util::beginsWith($lines[$n], '*/') || SRA_Util::endsWith($lines[$n], '*/')) {
$code = '$metadata';
foreach($mergePoint as $key) { $code .= "[$key]"; }
eval($code . ' = array_merge(' . $code . ', $api);');
}
break;
}
}
}
if ($cache) {
SRA_Cache::setCache($ckey, $metadata);
}
return $metadata;
}
// }}}
// {{{ parseDtd
/**
* used to parse a DTD. the return value will be a hash with the following
* values:
* comment: any comments provided for the DTD
* entities: a hash of DTD entities indexed by entity name with the
* following sub-keys:
* name: the entity name
* value: the entity value
* comment: the entity comment
* elements: a hash of DTD elements indexed by element name with the
* following sub-keys:
* name: the element name
* comment: the element comment
* elements: an array of sub-elements where the value contains the
* following sub-keys:
* name: the sub-element name
* set: if the sub-element is a choice of different sub-elements,
* this sub-key will be populated instead of 'name' which is
* an array of the names of possible sub-elements
* required: whether or not this sub-element is required
* many: whether or not many of these sub-elements may exist (if
* FALSE, only 1 sub-element of this type may exist)
* mixed: TRUE if the sub-elements are mixed (* modified) - meaning
* this element may contain zero or more occurrences of them
* attributes: an array of attributes that this element may contain
* indexed by attribute name where each attribute may have the
* following sub-keys:
* name: the attribute name
* comment: the attribute comment
* options: if this attribute can be one of a set of options, this
* attribute will be an array representing those options
* type: the attribute type, either CDATA, PCDATA, ID, IDREF,
* 'options' (if 'options' is set), or an entity name
* default: the default value
* required: whether or not this attribute is required
* used: an array of names of other elements where this element is
* used (not specified for the root element)
* root: the name of the root element
* @param string $file the absolute path to the DTD to parse
* @param boolean $cache whether or not the parse results should be cached
* (cache will be updated if the source file changes)
* @return mixed
*/
function parseDtd($file, $cache=TRUE) {
if (!file_exists($file)) {
return NULL;
}
$ckey = 'sra_parse_dtd_' . str_replace('/', '.', $file);
if ($cache) include_once('SRA_Cache.php');
if ($cache && ($modtime = SRA_Cache::cacheIsset($ckey, TRUE)) && $modtime > filemtime($file)) {
return SRA_Cache::getCache($ckey);
}
$inComment = FALSE;
$comments = array();
$metadata = array('comment' => NULL, 'entities' => array(), 'elements' => array(), 'root' => NULL);
$lines = file($file);
foreach(array_keys($lines) as $i) {
$m = NULL;
$line = trim($lines[$i]);
if (!$line && !$inComment) continue;
// comment end
if ($inComment && SRA_Util::endsWith($line, '-->')) {
$comment .= substr($line, 0, strpos($line, '-->'));
$inComment = FALSE;
if (trim($comment)) array_push($comments, $comment);
}
// add to comment
else if ($inComment) {
if (!preg_match('/Used in:/i', $line)) $comment .= $lines[$i];
}
// comment start
else if (!$inComment && SRA_Util::beginsWith($line, '<!--')) {
$comment = substr($line, 4);
$inComment = TRUE;
}
// entity
else if (preg_match('/<![\s]*entity[\s]*%[\s]*([\S]+)[\s]*([\S]+)[\s]*>/i', $line, $m)) {
$metadata['entities'][$m[1]] = array('name' => $m[1], 'value' => SRA_Util::stripQuotes($m[2]));
if (count($comments)) $metadata['entities'][$m[1]]['comment'] = array_pop($comments);
}
// element
else if (preg_match('/<![\s]*element[\s]+([\S]+)[\s]*\(([\s\S]+)\)([*]?)[\s]*>/i', $line, $m) || preg_match('/<![\s]*element[\s]+([\S]+)[\s]*([\S]+)[\s]*>/i', $line, $m)) {
$metadata['elements'][$m[1]] = array('name' => $m[1]);
if (trim(strtolower($m[2])) != 'empty') {
$metadata['elements'][$m[1]]['elements'] = array();
$metadata['elements'][$m[1]]['mixed'] = $m[3] == '*';
$m[2] = SRA_Util::stripQuotes($m[2], '(', ')');
$m[2] = explode(',', $m[2]);
$subelements = array();
foreach($m[2] as $name) {
$name = trim($name);
$mod = NULL;
if (SRA_Util::endsWith($name, '*') || SRA_Util::endsWith($name, '+') || SRA_Util::endsWith($name, '?')) {
$mod = substr($name, -1, 1);
$name = substr($name, 0, -1);
}
$set = NULL;
if (strpos($name, '|')) {
$name = SRA_Util::stripQuotes($name, '(', ')');
$set = explode('|', $name);
foreach(array_keys($set) as $skey) {
$set[$skey] = trim($set[$skey]);
}
}
$subelement = array();
$subelement[$set ? 'set' : 'name'] = $set ? $set : $name;
$subelement['required'] = $mod != '*' && $mod != '?' ? TRUE : FALSE;
$subelement['many'] = $mod && $mod != '?' ? TRUE : FALSE;
$metadata['elements'][$m[1]]['elements'][] = $subelement;
}
}
if (count($comments)) $metadata['elements'][$m[1]]['comment'] = array_pop($comments);
}
// attribute
else if (($inAttrList && preg_match('/[\s]*([\S]+)[\s]+([\S]+)[\s]+([\S]+)/', $line, $m)) || (!$inAttrList && preg_match('/<![\s]*attlist[\s]+([\S]+)[\s]+([\S]+)[\s]+([\S]+)[\s]+([\S]+)/i', $line, $m)) || (!$inAttrList && preg_match('/<![\s]*attlist[\s]+([\S]+)/i', $line, $m))) {
if (count($m) < 3) {
$attrElement = $m[1];
$inAttrList = TRUE;
continue;
}
$attrElement = trim($inAttrList ? $attrElement : $m[1]);
$name = trim($inAttrList ? $m[1] : $m[2]);
$type = trim($inAttrList ? $m[2] : $m[3]);
if (substr($type, 0, 1) == '%' && substr($type, -1, 1) == ';') $type = substr($type, 1, -1);
$default = trim($inAttrList ? $m[3] : $m[4]);
if (substr($default, -1, 1) == '>') $default = substr($default, 0, -1);
$inAttrList = preg_match('/>/', $line) ? FALSE : TRUE;
if (!isset($metadata['elements'][$attrElement])) $metadata['elements'][$attrElement] = array('name' => $attrElement);
if (!isset($metadata['elements'][$attrElement]['attributes'])) $metadata['elements'][$attrElement]['attributes'] = array();
$metadata['elements'][$attrElement]['attributes'][$name] = array('name' => $name, 'type' => $type, 'required' => strtolower($default) == '#required');
if (substr($default, 0, 1) != '#') {
$metadata['elements'][$attrElement]['attributes'][$name]['default'] = $default;
}
if (substr($type, 0, 1) == '(' && substr($type, -1, 1) == ')') {
$type = SRA_Util::stripQuotes($type, '(', ')');
$options = explode('|', $type);
foreach(array_keys($options) as $okey) {
$options[$okey] = trim($options[$okey]);
}
$metadata['elements'][$attrElement]['attributes'][$name]['options'] = $options;
$metadata['elements'][$attrElement]['attributes'][$name]['type'] = 'options';
}
}
// end attribute
else if ($inAttrList && preg_match('/>/', $line)) {
$inAttrList = FALSE;
}
}
// extract attribute comments from element if applicable
foreach(array_keys($metadata['elements']) as $element) {
if (isset($metadata['elements'][$element]['comment']) && isset($metadata['elements'][$element]['attributes'])) {
$comment = explode("\n", $metadata['elements'][$element]['comment']);
$ckeys = array_keys($comment);
foreach(array_keys($metadata['elements'][$element]['attributes']) as $attr) {
if (!isset($metadata['elements'][$element]['attributes'][$attr]['comment'])) {
$inComment = FALSE;
$acomment = '';
foreach($ckeys as $ckey) {
if (!isset($comment[$ckey])) continue;
if (!$inComment && preg_match('/^' . $attr . '[\s]+/', $comment[$ckey])) {
$acomment = trim(substr($comment[$ckey], strlen($attr) + 1));
$commentBuff = '';
for($i=0; $i<strlen($comment[$ckey]) - strlen($acomment)-1; $i++) {
$commentBuff .= ' ';
}
unset($comment[$ckey]);
$inComment = TRUE;
}
else if ($inComment && (!$comment[$ckey] || preg_match('/^[\s]/', $comment[$ckey]))) {
$acomment .= "\n" . str_replace($commentBuff, '', str_replace(' ', ' ', $comment[$ckey]));
unset($comment[$ckey]);
}
else if ($inComment) {
$inComment = FALSE;
break;
}
}
if ($acomment) {
$metadata['elements'][$element]['attributes'][$attr]['comment'] = $acomment;
}
}
}
$metadata['elements'][$element]['comment'] = trim(implode("\n", $comment));
}
}
// Determine root element
$elements = array();
foreach(array_keys($metadata['elements']) as $element) {
if (!isset($elements[$element])) {
$elements[$element] = array();
}
foreach(array_keys($metadata['elements'][$element]['elements']) as $i) {
$subelements = isset($metadata['elements'][$element]['elements'][$i]['name']) ? array($metadata['elements'][$element]['elements'][$i]['name']) : $metadata['elements'][$element]['elements'][$i]['set'];
foreach($subelements as $subelement) {
if (substr($subelement, 0, 1) == '#') continue;
if (!isset($elements[$subelement])) {
$elements[$subelement] = array();
}
$elements[$subelement][] = $element;
}
}
}
foreach($elements as $element => $within) {
if (!$within) {
$metadata['root'] = $element;
}
else {
$metadata['elements'][$element]['used'] = $within;
}
}
// DTD comment
if (count($comments)) {
while($comment = array_pop($comments)) {
if (SRA_Util::beginsWith(trim($comment), '+~~')) continue;
$metadata['comment'] = $comment;
break;
}
}
if ($cache) {
SRA_Cache::setCache($ckey, $metadata);
}
return $metadata;
}
// }}}
// {{{ validateStaticMethodPath
/**
* used to validate a static method path which is a class path followed by two
* colons and the method name. to do so, this method includes the class file
* and verifies that the method exists in the class. returns TRUE if the path
* is valid, FALSE otherwise. Here are some examples of static method paths:
* 'users/User::validateEmail' - looks for class in
* [app]/lib/users/User.php and method
* 'validateEmail' in that class
* NOTE: the .php extension is not needed
* @param string $path the static method path to validate
* @param boolean $returnFilePath when true, the absolute path to the PHP
* source file will be returned if $path is valid instead of TRUE or FALSE
* @access public
* @return mixed
*/
function validateStaticMethodPath($path, $returnFilePath=FALSE) {
$valid = FALSE;
$phpExt = '.' . SRA_SYS_PHP_EXTENSION;
if (preg_match('/(.*)::(.*)/', $path, $m) && count($m) == 3 && file_exists($file = SRA_File::getRelativePath(FALSE, $m[1] . (SRA_Util::endsWith($m[1], $phpExt) ? '' : $phpExt), 'lib'))) {
include_once($file);
$valid = in_array($m[2], get_class_methods(substr(basename($file), 0, strlen($phpExt)*-1)));
}
return $returnFilePath && $valid && $file ? $file : $valid;
}
// }}}
// {{{ invokeStaticMethodPath
/**
* invokes a static method using a static method path (see
* 'validateStaticMethodPath' above) and returns the results of invoking that
* method. returns NULL if the method is not valid
* @param string $path the path to static method to invoke
* @param array $params an array of parameters to invoke. these will be
* passed into the method as arguments where the first value in the array is
* the first argument, the 2nd is the second, and so on. this parameter is
* optional
* @access public
* @return mixed
*/
function &invokeStaticMethodPath($path, &$params) {
$ret = NULL;
$phpExt = '.' . SRA_SYS_PHP_EXTENSION;
if ((!$params || is_array($params)) && preg_match('/(.*)::(.*)/', $path, $m) && count($m) == 3 && file_exists($file = SRA_File::getRelativePath(FALSE, $m[1] . (SRA_Util::endsWith($m[1], $phpExt) ? '' : $phpExt), 'lib'))) {
include_once($file);
if (in_array($methodName = $m[2], get_class_methods($className = substr(basename($file), 0, strlen($phpExt)*-1)))) {
$code = '$ret =& ' . $className . '::' . $methodName . '(';
if ($params) {
$keys = array_keys($params);
foreach($keys as $key) {
$code .= $key == $keys[0] ? '' : ', ';
$code .= '$params[' . $key . ']';
}
}
$code .= ');';
eval($code);
}
}
return $ret;
}
// }}}
// {{{ getStaticMethodPathApi
/**
* returns the api (if $path is properly documented) for the class and method
* defined by $path. this is a hash with the same keys as defined for methods
* in SRA_Util::parsePhpSource. returns NULL if unsuccessful
* @param string $path the static method path to return the api for
* @access public
* @return hash
*/
function getStaticMethodPathApi($path) {
if (($api =& SRA_Util::parsePhpSource(SRA_Util::validateStaticMethodPath($path, TRUE))) && isset($api['classes'])) {
foreach(array_keys($api['classes']) as $key) {
if (isset($api['classes'][$key]['name']) && strpos($path, $api['classes'][$key]['name'] . '::') !== FALSE && isset($api['classes'][$key]['methods'])) {
foreach(array_keys($api['classes'][$key]['methods']) as $mkey) {
if (strpos($path, $api['classes'][$key]['name'] . '::' . $api['classes'][$key]['methods'][$mkey]['name']) !== FALSE) {
return $api['classes'][$key]['methods'][$mkey];
}
}
}
}
}
return NULL;
}
// }}}
// {{{ ping
/**
* pings $host and returns TRUE if it is reachable, FALSE otherwise
* @param string $host the host to ping. either a hostname or IP address
* @access public
* @return boolean
*/
function ping($host) {
require_once('model/SRA_AttributeValidator.php');
$ip = SRA_AttributeValidator::ip($host) ? $host : gethostbyname($host);
$ping = shell_exec(SRA_File::findInPath('ping') . ' -c 1 -w 1 ' . $ip);
return SRA_AttributeValidator::ip($ip) && preg_match('/ 0% packet loss/', $ping) ? TRUE : FALSE;
}
// }}}
// {{{ fork
/**
* executes a command as a new process. this command will fork off the current
* php process and thus will not stall execution. returns the PID of the
* forked command if successful
* @param string $cmd the command to fork
* @access public
* @return int
*/
function fork($cmd) {
exec($cmd . ' > /dev/null 2>&1 &');
return SRA_Util::getProcessId($cmd);
}
// }}}
// {{{ getServiceName
/**
* uses the /etc/services file to attempt to determine the name of the service
* for a given port
* @param int $port the port to lookup
* @param string $proto the protocol (tcp or udp)
* @access public
* @return string
*/
function getServiceName($port, $proto='tcp') {
static $_utilServiceMappings;
if (!$_utilServiceMappings && file_exists(SRA_UTIL_SERVICES_CONFIG)) {
$_utilServiceMappings = array();
foreach(file(SRA_UTIL_SERVICES_CONFIG) as $line) {
if (preg_match('/^(\S*)\s*(\S*)\s/', $line, $m)) {
$_utilServiceMappings[$m[2]] = $m[1];
}
}
}
return $_utilServiceMappings && isset($_utilServiceMappings[$port . '/' . $proto]) ? $_utilServiceMappings[$port . '/' . $proto] : NULL;
}
// }}}
// {{{ getServicePort
/**
* uses the /etc/services file to attempt to determine the port used by
* $services
* @param string $service the name of the service to return the port for
* @access public
* @return int
*/
function getServicePort($service) {
static $_utilServiceMappings1;
if (!$_utilServiceMappings1 && file_exists(SRA_UTIL_SERVICES_CONFIG)) {
$_utilServiceMappings1 = array();
foreach(file(SRA_UTIL_SERVICES_CONFIG) as $line) {
if (preg_match('/^(\S*)\s*(\S*)\s/', $line, $m)) {
$tmp = explode('/', $m[2]);
$_utilServiceMappings1[strtolower($m[1])] = $tmp[0]*1;
}
}
}
return $_utilServiceMappings1 && isset($_utilServiceMappings1[strtolower($service)]) ? $_utilServiceMappings1[strtolower($service)] : NULL;
}
// }}}
// {{{ isPrivateNetworkIp
/**
* returns TRUE if $ip is on a private IPv4 network (10.0.0.0-10.255.255.255
* OR 172.16.0.0-172.31.255.255 OR 192.168.0.0-192.168.255.255)
* @param string $ip the IP address to check
* @access public
* @return boolean
*/
function isPrivateNetworkIp($ip) {
$pieces = explode('.', $ip);
return count($pieces) == 4 && ($pieces[0] == 10 || ($pieces[0] == 172 && $pieces[1] >= 16 && $pieces[1] <= 31) || ($pieces[0] == 192 && $pieces[1] == 168)) ? TRUE : FALSE;
}
// }}}
// {{{ createThumbnail
/**
* creates a thumbnail image using the php gd image manipulation functions.
* returns TRUE on success, FALSE otherwise. the proportional dimensions of
* the image will be maintained, so the thumbnail image will have either
* height=$height OR width=$width but not both and neither height nor width in
* the thumbnail will exceed the $height and $width specified. this method
* uses ImageMagick if it is installed, php-gd otherwise
* @param string $src the source image. should have a correct file extension:
* jpg, gif or png
* @param int $theight the maximum height. at least 1, theight or twidth must
* be specified
* @param int $twidth the maximum width. at least 1, theight or twidth must be
* specified
* @param string $thumb path to the thumbnail image that should be created. if
* not specified, the new image will be named the same as $src but with a "-t"
* suffix (preceeding the file extension)
* @access public
* @return boolean
*/
function createThumbnail($src, $theight, $twidth, $thumb) {
$ret = FALSE;
if ((($imageMagick = SRA_File::findInPath(SRA_FILE_ATTRIBUTE_IMAGE_MAGICK_CONVERT)) || function_exists('imagecreatefromjpeg')) &&
($attrs = getimagesize($src)) && $attrs[0] && $attrs[1] && $attrs[2] && ($theight || $twidth)) {
$ewidth = $attrs[0];
$eheight = $attrs[1];
if (!$theight) $theight = $twidth;
if (!$twidth) $twidth = $theight;
if ($ewidth > $eheight) {
$width = $twidth;
$height = round($eheight*($theight/$ewidth));
}
if ($ewidth < $eheight) {
$width = round($ewidth*($twidth/$eheight));
$height = $theight;
}
if ($ewidth == $eheight) {
$width = $twidth;
$height = $theight;
}
$thumb = $thumb ? $thumb : dirname($src) . '/' . SRA_Util::getFileNameWOExtension($src) . '-t.' . SRA_Util::getFileExtension($src);
if ($imageMagick) {
$cmd = $imageMagick . ' -thumbnail ' . $width . 'x' . $height . ' ' . $src . '[0] ' . $thumb;
exec($cmd);
$ret = file_exists($thumb);
}
else {
switch($attrs[2]) {
case IMAGETYPE_GIF:
$i = imagecreatefromgif($src);
break;
case IMAGETYPE_JPEG:
$i = imagecreatefromjpeg($src);
break;
case IMAGETYPE_PNG:
$i = imagecreatefrompng($src);
break;
}
if ($i) {
$t = ImageCreateTrueColor($width, $height);
imagecopyresampled($t, $i, 0, 0, 0, 0, $width, $height, $ewidth, $eheight);
switch($attrs[2]) {
case IMAGETYPE_GIF:
imagegif($t, $thumb);
break;
case IMAGETYPE_JPEG:
imagejpeg($t, $thumb);
break;
case IMAGETYPE_PNG:
imagepng($t, $thumb);
break;
}
imagedestroy($i);
$ret = $t ? TRUE : FALSE;
if ($t) imagedestroy($t);
}
}
}
return $ret;
}
// }}}
/**
* PHP implementation of the Porter Stemming Algorithm written by Iain Argent
* for Complinet Ltd., 17/2/00. Translated from the PERL version at
* http://www.muscat.com/~martin/p.txt. Version 1.1 (Includes British English
* endings). Reduces words to their base stem for search engines and indexing
* this code was borrowed from http://www.weberdev.com/get_example-1503.html
* @param string $word the word to step
* @return string
*/
function stem($word) {
$step2list=array('ational'=>'ate', 'tional'=>'tion', 'enci'=>'ence',
'anci'=>'ance', 'izer'=>'ize', 'iser'=>'ise', 'bli'=>'ble',
'alli'=>'al', 'entli'=>'ent', 'eli'=>'e', 'ousli'=>'ous',
'ization'=>'ize', 'isation'=>'ise', 'ation'=>'ate',
'ator'=>'ate', 'alism'=>'al', 'iveness'=>'ive',
'fulness'=>'ful', 'ousness'=>'ous', 'aliti'=>'al',
'iviti'=>'ive', 'biliti'=>'ble', 'logi'=>'log');
$step3list=array('icate'=>'ic', 'ative'=>'', 'alize'=>'al', 'alise'=>'al',
'iciti'=>'ic', 'ical'=>'ic', 'ful'=>'', 'ness'=>'');
$c = "[^aeiou]"; # consonant
$v = "[aeiouy]"; # vowel
$C = "${c}[^aeiouy]*"; # consonant sequence
$V = "${v}[aeiou]*"; # vowel sequence
$mgr0 = "^(${C})?${V}${C}"; # [C]VC... is m>0
$meq1 = "^(${C})?${V}${C}(${V})?" . '$'; # [C]VC[V] is m=1
$mgr1 = "^(${C})?${V}${C}${V}${C}"; # [C]VCVC... is m>1
$_v = "^(${C})?${v}"; # vowel in stem
if (strlen($word)<3) return $word;
$word=preg_replace("/^y/", "Y", $word);
#Step 1a
$word=preg_replace("/(ss|i)es$/", "\\1", $word); # sses-> ss, ies->es
$word=preg_replace("/([^s])s$/", "\\1", $word); # ss->ss but s->null
#Step 1b
if (preg_match("/eed$/", $word)) {
$stem=preg_replace("/eed$/", '', $word);
if (ereg("$mgr0", $stem)) {
$word=preg_replace("/.$/", '', $word);
}
}
elseif (preg_match("/(ed|er|ing)$/", $word)) {
$stem=preg_replace("/(ed|er|ing)$/", '', $word);
if (preg_match("/$_v/", $stem)) {
$word=$stem;
if (preg_match("/(at|bl|iz|is)$/", $word)) {
$word=preg_replace("/(at|bl|iz|is)$/", "\\1e", $word);
}
elseif (preg_match("/([^aeiouylsz])\\1$/", $word)) {
$word=preg_replace("/.$/", '', $word);
}
elseif (preg_match("/^${C}${v}[^aeiouwxy]$/", $word)) {
$word.="e";
}
}
}
#Step 1c (weird rule)
if (preg_match("/y$/", $word)) {
$stem=preg_replace("/y$/", '', $word);
if (preg_match("/$_v/", $stem))
$word=$stem."i";
}
#Step 2
if (preg_match("/(ational|tional|enci|anci|izer|iser|bli|alli|entli|eli|ousli|ization|isation|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/", $word, $matches)) {
$stem=preg_replace("/(ational|tional|enci|anci|izer|iser|bli|alli|entli|eli|ousli|ization|isation|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/",'', $word);
$suffix=$matches[1];
if (preg_match("/$mgr0/", $stem)) {
$word=$stem.$step2list[$suffix];
}
}
#Step 3
if (preg_match("/(icate|ative|alize|alise|iciti|ical|ful|ness)$/", $word, $matches)) {
$stem=preg_replace("/(icate|ative|alize|alise|iciti|ical|ful|ness)$/", '', $word);
$suffix=$matches[1];
if (preg_match("/$mgr0/", $stem)) {
$word=$stem.$step3list[$suffix];
}
}
#Step 4
if (preg_match("/(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize|ise)$/", $word, $matches)) {
$stem=preg_replace("/(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize|ise)$/", '', $word);
$suffix=$matches[1];
if (preg_match("/$mgr1/", $stem)) {
$word=$stem;
}
}
elseif (preg_match("/(s|t)ion$/", $word)) {
$stem=preg_replace("/(s|t)ion$/", "\\1", $word);
if (preg_match("/$mgr1/", $stem)) $word=$stem;
}
#Step 5
if (preg_match("/e$/", $word, $matches)) {
$stem=preg_replace("/e$/", '', $word);
if (preg_match("/$mgr1/", $stem) | (preg_match("/$meq1/", $stem) & ~preg_match("/^${C}${v}[^aeiouwxy]$/", $stem))) {
$word=$stem;
}
}
if (preg_match("/ll$/", $word) & preg_match("/$mgr1/", $word)) $word=preg_replace("/.$/", '', $word);
# and turn initial Y back to y
preg_replace("/^Y/", "y", $word);
return $word;
}
/**
* parses a URI and return the pieces as a hash containing the following
* possible keys (values not present in the URI will not in the hash):
* user: username
* pswd: password
* protocol: protocol (i.e. http, https, ftp) - always lowercase
* host: hostname or IP - always lowercase
* port: port
* path: url path
* params: hash of URI parameters
* this method is not case sensitive. for example, the $uri
* "Https://test:hide@address.com:32/test/script?hello=world&hi=yes" would result in the
* following hash being returned:
* user => test
* pswd => mypass
* protocol => https
* host => test.com
* port => 32
* path => /test/script
* params => (hash)
* hello => world
* hi => yes
* @param string $uri the uri to parse
* @return hash
*/
function parseUri($uri) {
$parsed = NULL;
if (preg_match('/([a-zA-Z]+):\/\/((.*)@)?([a-zA-Z0-9\.\-]+)(:([0-9]+))?(\/.*)?(\?(.*))?/i', trim($uri), $m)) {
$parsed = array();
if ($m[3]) {
if ($tmp = strpos($m[3], ':')) {
$parsed['user'] = substr($m[3], 0, $tmp);
$parsed['pswd'] = substr($m[3], $tmp + 1);
}
else {
$parsed['user'] = $m[3];
}
}
$parsed['protocol'] = strtolower($m[1]);
$parsed['host'] = strtolower($m[4]);
if (count($m) > 5) {
if ($m[6]) $parsed['port'] = $m[6]*1;
if ($m[7]) {
if ($tmp = strpos($m[7], '?')) {
$parsed['path'] = substr($m[7], 0, $tmp);
$params = array();
foreach(explode('&', substr($m[7], $tmp + 1)) as $param) {
$params[substr($param, 0, $tmp = strpos($param, '='))] = substr($param, $tmp + 1);
}
$parsed['params'] = $params;
}
else {
$parsed['path'] = $m[7];
}
}
}
}
return $parsed;
}
/**
* converts an object to a hash recursively using get_object_vars
* @param object $obj the object to convert
* @return hash
*/
function objToHash(&$obj) {
if (is_object($obj)) {
$hash = get_object_vars($obj);
foreach(array_keys($hash) as $key) {
if (is_object($hash[$key])) {
$hash[$key] = SRA_Util::objToHash($hash[$key]);
}
}
}
return $hash;
}
/**
* may be used to lookup MX DNS records. the return value will be an array of
* hashes each with the following keys
* @param string $domain the domain to lookup
* @param string $dns the dns server to use
* @param int $timeout the amount of time to wait for a response before
* timing out
* @return boolean
*/
function mxlookup($domain, $dns, $timeout=2) {
$mx = new _mxlookup($domain, $dns, $timeout);
return $mx->arrMX ? $mx->arrMX : NULL;
}
/**
* checks if port is already in use by attempting to make a tcp socket
* connection
* @param int $port the port to check
* @param string $host the host to verify the port on. if not specified,
* localhost will be used
* @param int $timeout the amount of time in seconds to wait for a response
* @return boolean
*/
function portInUse($port, $host='localhost', $timeout=1) {
if ($sock = fsockopen("tcp://$host", $port, $errno, $errstr, $timeout)) {
fclose($sock);
return TRUE;
}
else {
return FALSE;
}
}
/**
* generates a random password based on the parameters specified
* @param int $length the desired password length - must be between 2 and 64
* @param int $strength the desired password strength - either 1, 2, or 3
* where 1 is the weakest and 3 is the strongest
* @return string
*/
function generatePassword($length=8,$level=2){
list($usec, $sec) = explode(' ', microtime());
srand((float) $sec + ((float) $usec * 100000));
$length = is_int($length) && $length > 1 && $length < 64 ? $length : 8;
$level = $level != 1 && $level != 2 && $level != 3 ? 2 : $level;
$validchars = array();
$validchars[1] = "0123456789abcdfghjkmnpqrstvwxyz";
$validchars[2] = "0123456789abcdfghjkmnpqrstvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$validchars[3] = "0123456789_!@#$%&*()-=+/abcdfghjkmnpqrstvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_!@#$%&*()-=+/";
$password = "";
$counter = 0;
while ($counter < $length) {
$actChar = substr($validchars[$level], rand(0, strlen($validchars[$level])-1), 1);
// All character must be different
if (!strstr($password, $actChar)) {
$password .= $actChar;
$counter++;
}
}
return $password;
}
/**
* converts any empty strings in $hash to NULL
* @param array $hash the hash to convert
* @param boolean $unsetArr whether or not to unset empty string (or NULL)
* sub-elements of $hash
* @return void
*/
function emptyStringToNull(&$hash, $unsetArr=TRUE) {
if (is_array($hash)) {
foreach(array_keys($hash) as $key) {
if (is_string($hash[$key]) && !trim($hash[$key])) {
$hash[$key] = NULL;
}
else if (is_array($hash[$key])) {
SRA_Util::emptyStringToNull($hash[$key]);
$setNull = TRUE;
foreach(array_keys($hash[$key]) as $akey) {
if ($hash[$key][$akey] !== NULL) {
$setNull = FALSE;
break;
}
else if ($unsetArr) {
unset($hash[$key][$akey]);
}
}
if ($setNull) $hash[$key] = NULL;
}
}
}
}
/**
* removes an item or items from $arr matching the regular expression $regex
* where the items that are removed use keys or values that match $regex
* @param array $arr the array to operate on
* @param string $regex the regular expression to match
* @param boolean $matchKey whether or not to match the array key (default is
* TRUE). if FALSE, array value will be matched
* @return void
*/
function removeKeyFromArray(&$arr, $regex, $matchKey=TRUE) {
foreach(array_keys($arr) as $key) {
if (preg_match($regex, $matchKey ? $key : $arr[$key])) {
unset($arr[$key]);
}
}
}
}
// }}}
// {{{ codeToString()
/**
* Used function used to forward to SRA_Util:: function (see method api for more
* info)
*/
function codeToString($code) {
return SRA_Util::codeToString($code);
}
// }}}
/**
* utility class uses by SRA_Util::mxlookup
*/
class _mxlookup {
var $dns_socket = NULL;
var $QNAME = "";
var $dns_packet= NULL;
var $ANCOUNT = 0;
var $cIx = 0;
var $dns_repl_domain;
var $arrMX = array();
function _mxlookup($domain, $dns, $timeout)
{
$this->QNAME($domain);
$this->pack_dns_packet();
$dns_socket = fsockopen("udp://$dns", 53);
fwrite($dns_socket,$this->dns_packet,strlen($this->dns_packet));
@socket_set_timeout($dns_socket, $timeout);
$this->dns_reply = fread($dns_socket,1);
$bytes = stream_get_meta_data($dns_socket);
$this->dns_reply .= fread($dns_socket,$bytes['unread_bytes']);
fclose($dns_socket);
$this->cIx=6;
$this->ANCOUNT = $this->gord(2);
$this->cIx+=4;
$this->parse_data($this->dns_repl_domain);
$this->cIx+=7;
for($ic=1;$ic<=$this->ANCOUNT;$ic++)
{
$QTYPE = ord($this->gdi($this->cIx));
if($QTYPE!==15){print("[MX Record not returned]"); die();}
$this->cIx+=9;
$mxPref = ord($this->gdi($this->cIx));
$this->parse_data($curmx);
$this->arrMX[] = array("MX_Pref" => $mxPref, "MX" => $curmx);
$this->cIx+=3;
}
}
function parse_data(&$retval)
{
$arName = array();
$byte = ord($this->gdi($this->cIx));
while($byte!==0)
{
if($byte==192) //compressed
{
$tmpIx = $this->cIx;
$this->cIx = ord($this->gdi($cIx));
$tmpName = $retval;
$this->parse_data($tmpName);
$retval=$retval.".".$tmpName;
$this->cIx = $tmpIx+1;
return;
}
$retval="";
$bCount = $byte;
for($b=0;$b<$bCount;$b++)
{
$retval .= $this->gdi($this->cIx);
}
$arName[]=$retval;
$byte = ord($this->gdi($this->cIx));
}
$retval=join(".",$arName);
}
function gdi(&$cIx,$bytes=1)
{
$this->cIx++;
return(substr($this->dns_reply, $this->cIx-1, $bytes));
}
function QNAME($domain)
{
$dot_pos = 0; $temp = "";
while($dot_pos=strpos($domain,"."))
{
$temp = substr($domain,0,$dot_pos);
$domain = substr($domain,$dot_pos+1);
$this->QNAME .= chr(strlen($temp)).$temp;
}
$this->QNAME .= chr(strlen($domain)).$domain.chr(0);
}
function gord($ln=1)
{
$reply="";
for($i=0;$i<$ln;$i++){
$reply.=ord(substr($this->dns_reply,$this->cIx,1));
$this->cIx++;
}
return $reply;
}
function pack_dns_packet()
{
$this->dns_packet = chr(0).chr(1).
chr(1).chr(0).
chr(0).chr(1).
chr(0).chr(0).
chr(0).chr(0).
chr(0).chr(0).
$this->QNAME.
chr(0).chr(15).
chr(0).chr(1);
}
}
?>