Overview

Namespaces

  • GAubry
    • ErrorHandler
    • Helpers
    • Logger
    • Shell
  • Himedia
    • Padocc
      • DB
      • Minifier
      • Numbering
      • Properties
      • Task
        • Base
        • Extended
  • None
  • Psr
    • Log

Classes

  • Debug
  • Helpers
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: namespace GAubry\Helpers;
  4: 
  5: /**
  6:  * Some helpers used in several personal packages.
  7:  * @SuppressWarnings(TooManyMethods)
  8:  *
  9:  * Copyright (c) 2013 Geoffroy Aubry <geoffroy.aubry@free.fr>
 10:  * Licensed under the GNU Lesser General Public License v3 (LGPL version 3).
 11:  *
 12:  * @copyright 2013 Geoffroy Aubry <geoffroy.aubry@free.fr>
 13:  * @license http://www.gnu.org/licenses/lgpl.html
 14:  */
 15: class Helpers
 16: {
 17:     /**
 18:      * @codeCoverageIgnore
 19:      */
 20:     private function __construct()
 21:     {
 22:     }
 23: 
 24:     /**
 25:      * Flatten a multidimensional array (keys are ignored).
 26:      *
 27:      * @param array $aArray
 28:      * @return array a one dimensional array.
 29:      * @see http://stackoverflow.com/a/1320156/1813519
 30:      */
 31:     public static function flattenArray (array $aArray)
 32:     {
 33:         $aFlattened = array();
 34:         array_walk_recursive(
 35:             $aArray,
 36:             function ($mValue) use (&$aFlattened) {
 37:                 $aFlattened[] = $mValue;
 38:             }
 39:         );
 40:         return $aFlattened;
 41:     }
 42: 
 43:     /**
 44:      * Returns the UTF-8 translation of the specified string, only if not already in UTF-8.
 45:      *
 46:      * @param string $s
 47:      * @return string the UTF-8 translation of the specified string, only if not already in UTF-8.
 48:      */
 49:     public static function utf8Encode ($str)
 50:     {
 51:         return (preg_match('//u', $str) === 1 ? $str : utf8_encode($str));
 52:     }
 53: 
 54:     /**
 55:      * Executes the given shell command and returns an array filled with every line of output from the command.
 56:      * Trailing whitespace, such as \n, is not included in this array.
 57:      * On shell error (exit code <> 0), throws a \RuntimeException with error message..
 58:      *
 59:      * @param string $sCmd shell command
 60:      * @param string $sOutputPath optional redirection of standard output
 61:      * @param string $sErrorPath optional redirection of standard error
 62:      * @param bool $bAppend true to append to specified files
 63:      * @return array array filled with every line of output from the command
 64:      * @throws \RuntimeException if shell error
 65:      */
 66:     public static function exec ($sCmd, $sOutputPath = '', $sErrorPath = '', $bAppend = false)
 67:     {
 68:         // set STDOUT and STDERR
 69:         $sAppending = ($bAppend ? '>>' : '>');
 70:         if (empty($sOutputPath)) {
 71:             if (empty($sErrorPath)) {
 72:                 $sStreams = '2>&1';
 73:             } else {
 74:                 $sStreams = "2$sAppending$sErrorPath";
 75:             }
 76:         } elseif (empty($sErrorPath)) {
 77:             $sStreams = "2>&1 1$sAppending$sOutputPath";
 78:         } else {
 79:             $sStreams = "1$sAppending$sOutputPath 2$sAppending$sErrorPath";
 80:         }
 81: 
 82:         // execute cmd
 83:         $sFullCmd = "( $sCmd ) $sStreams";
 84:         exec($sFullCmd, $aResult, $iReturnCode);
 85: 
 86:         // retrieve content of STDOUT and STDERR
 87:         if (empty($sOutputPath)) {
 88:             $aOutput = $aResult;
 89:             if (empty($sErrorPath)) {
 90:                 $aError = $aResult;
 91:             } else {
 92:                 $aError = file($sErrorPath, FILE_IGNORE_NEW_LINES);
 93:             }
 94:         } elseif (empty($sErrorPath)) {
 95:             $aOutput = file($sOutputPath, FILE_IGNORE_NEW_LINES);
 96:             $aError = $aResult;
 97:         } else {
 98:             $aOutput = file($sOutputPath, FILE_IGNORE_NEW_LINES);
 99:             $aError = file($sErrorPath, FILE_IGNORE_NEW_LINES);
100:         }
101: 
102:         // result
103:         if ($iReturnCode !== 0) {
104:             throw new \RuntimeException(
105:                 "Exit code not null: $iReturnCode. Result: '" . implode("\n", $aError) . "'",
106:                 $iReturnCode
107:             );
108:         }
109:         return $aOutput;
110:     }
111: 
112:     /**
113:      * Remove all Bash color sequences from the specified string.
114:      *
115:      * @param string $sMsg
116:      * @return string specified string without any Bash color sequence.
117:      */
118:     public static function stripBashColors ($sMsg)
119:     {
120:         return preg_replace('/\x1B\[([0-9]{1,2}(;[0-9]{1,2}){0,2})?[m|K]/', '', $sMsg);
121:     }
122: 
123:     /**
124:      * Rounds specified value with precision $iPrecision as native round() function, but keep trailing zeros.
125:      *
126:      * @param float $fValue value to round
127:      * @param int $iPrecision the optional number of decimal digits to round to (can also be negative)
128:      * @return string
129:      */
130:     public static function round ($fValue, $iPrecision = 0)
131:     {
132:         $sPrintfPrecision = max(0, $iPrecision);
133:         return sprintf("%01.{$sPrintfPrecision}f", round($fValue, $iPrecision));
134:     }
135: 
136:     /**
137:      * Returns a string with the first character of each word in specified string capitalized,
138:      * if that character is alphabetic.
139:      * Additionally, each character that is immediately after one of $aDelimiters will be capitalized too.
140:      *
141:      * @param string $sString
142:      * @param array $aDelimiters
143:      * @return string
144:      */
145:     public static function ucwordWithDelimiters ($sString, array $aDelimiters = array())
146:     {
147:         $sReturn = ucwords($sString);
148:         foreach ($aDelimiters as $sDelimiter) {
149:             if (strpos($sReturn, $sDelimiter) !== false) {
150:                 $sReturn = implode($sDelimiter, array_map('ucfirst', explode($sDelimiter, $sReturn)));
151:             }
152:         }
153:         return $sReturn;
154:     }
155: 
156:     /**
157:      * Returns specified value in the most appropriate unit, with that unit.
158:      * If $bBinaryPrefix is FALSE then use SI units (i.e. k, M, G, T),
159:      * else use IED units (i.e. Ki, Mi, Gi, Ti).
160:      * @see http://en.wikipedia.org/wiki/Binary_prefix
161:      *
162:      * @param int $iValue
163:      * @param bool $bBinaryPrefix
164:      * @return array a pair constituted by specified value in the most appropriate unit and that unit
165:      */
166:     public static function intToMultiple ($iValue, $bBinaryPrefix = false)
167:     {
168:         static $aAllPrefixes = array(
169:             10 => array(12 => 'T', 9 => 'G', 6 => 'M', 3 => 'k', 0 => ''),
170:             2 => array(40 => 'Ti', 30 => 'Gi', 20 => 'Mi', 10 => 'Ki', 0 => ''),
171:         );
172: 
173:         $iBase = ($bBinaryPrefix ? 2 : 10);
174:         $aPrefixes = $aAllPrefixes[$iBase];
175:         $iMaxMultiple = 0;
176:         foreach (array_keys($aPrefixes) as $iMultiple) {
177:             if ($iValue >= pow($iBase, $iMultiple)) {
178:                 $iMaxMultiple = $iMultiple;
179:                 break;
180:             }
181:         }
182: 
183:         return array($iValue / pow($iBase, $iMaxMultiple), $aPrefixes[$iMaxMultiple]);
184:     }
185: 
186:     /**
187:      * Format a number with grouped thousands.
188:      * It is an extended version of number_format() that allows do not specify $decimals.
189:      *
190:      * @param float $fNumber The number being formatted.
191:      * @param string $sDecPoint Sets the separator for the decimal point.
192:      * @param string $sThousandsSep Sets the thousands separator. Only the first character of $thousands_sep is used.
193:      * @param int $iDecimals Sets the number of decimal points.
194:      * @return string A formatted version of $number.
195:      */
196:     public static function numberFormat ($fNumber, $sDecPoint = '.', $sThousandsSep = ',', $iDecimals = null)
197:     {
198:         if ($iDecimals !== null) {
199:             return number_format($fNumber, $iDecimals, $sDecPoint, $sThousandsSep);
200:         } else {
201:             $tmp = explode('.', $fNumber);
202:             $out = number_format($tmp[0], 0, $sDecPoint, $sThousandsSep);
203:             if (isset($tmp[1])) {
204:                 $out .= $sDecPoint.$tmp[1];
205:             }
206:             return $out;
207:         }
208:     }
209: 
210:     /**
211:      * Formats a line passed as a fields array as CSV and return it, without the trailing newline.
212:      * Inspiration: http://www.php.net/manual/en/function.str-getcsv.php#88773
213:      *
214:      * @param array $aInput
215:      * @param string $sDelimiter
216:      * @param string $sEnclosure
217:      * @return string specified array converted into CSV format string
218:      */
219:     public static function strPutCSV ($aInput, $sDelimiter = ',', $sEnclosure = '"')
220:     {
221:         // Open a memory "file" for read/write...
222:         $hTmpFile = fopen('php://temp', 'r+');
223:         fputcsv($hTmpFile, $aInput, $sDelimiter, $sEnclosure);
224:         // ... rewind the "file" so we can read what we just wrote...
225:         rewind($hTmpFile);
226:         $sData = fgets($hTmpFile);
227:         fclose($hTmpFile);
228:         // ... and return the $data to the caller, with the trailing newline from fgets() removed.
229:         return rtrim($sData, "\n");
230:     }
231: 
232:     /**
233:      * array_merge_recursive() does indeed merge arrays, but it converts values with duplicate
234:      * keys to arrays rather than overwriting the value in the first array with the duplicate
235:      * value in the second array, as array_merge does. I.e., with array_merge_recursive(),
236:      * this happens (documented behavior):
237:      *
238:      * array_merge_recursive(array('key' => 'org value'), array('key' => 'new value'));
239:      *     ⇒ array('key' => array('org value', 'new value'));
240:      *
241:      * arrayMergeRecursiveDistinct() does not change the datatypes of the values in the arrays.
242:      * Matching keys' values in the second array overwrite those in the first array, as is the
243:      * case with array_merge, i.e.:
244:      *
245:      * arrayMergeRecursiveDistinct(array('key' => 'org value'), array('key' => 'new value'));
246:      *     ⇒ array('key' => array('new value'));
247:      *
248:      * EVO on indexed arrays:
249:      *   Before:
250:      *     arrayMergeRecursiveDistinct(array('a', 'b'), array('c')) ⇒ array('c', 'b')
251:      *   Now:
252:      *     ⇒ array('c')
253:      *
254:      * @param array $aArray1
255:      * @param array $aArray2
256:      * @return array An array of values resulted from strictly merging the arguments together.
257:      * @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk>
258:      * @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com>
259:      * @author Geoffroy Aubry
260:      * @see http://fr2.php.net/manual/en/function.array-merge-recursive.php#89684
261:      */
262:     public static function arrayMergeRecursiveDistinct (array $aArray1, array $aArray2)
263:     {
264:         $aMerged = $aArray1;
265:         if (self::isAssociativeArray($aMerged)) {
266:             foreach ($aArray2 as $key => &$value) {
267:                 if (is_array($value) && isset($aMerged[$key]) && is_array($aMerged[$key])) {
268:                     $aMerged[$key] = self::arrayMergeRecursiveDistinct($aMerged[$key], $value);
269:                 } else {
270:                     $aMerged[$key] = $value;
271:                 }
272:             }
273:         } else {
274:             $aMerged = $aArray2;
275:         }
276:         return $aMerged;
277:     }
278: 
279:     /**
280:      * Returns TRUE iff the specified array is associative.
281:      * If the specified array is empty, then return FALSE.
282:      *
283:      * http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential
284:      *
285:      * @param array $aArray
286:      * @return bool true ssi iff the specified array is associative
287:      */
288:     public static function isAssociativeArray (array $aArray)
289:     {
290:         foreach (array_keys($aArray) as $key) {
291:             if (! is_int($key)) {
292:                 return true;
293:             }
294:         }
295:         return false;
296:     }
297: }
298: 
Platform for Automatized Deployments with pOwerful Concise Configuration API documentation generated by ApiGen 2.8.0