]> git.mxchange.org Git - core.git/blob - framework/main/classes/utils/string/class_StringUtils.php
Continued:
[core.git] / framework / main / classes / utils / string / class_StringUtils.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Utils\String;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Configuration\FrameworkConfiguration;
8 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
9 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
10
11 // Import SPL stuff
12 use \InvalidArgumentException;
13
14 /**
15  * A string utility class
16  *
17  * @author              Roland Haeder <webmaster@ship-simu.org>
18  * @version             0.0.0
19  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
20  * @license             GNU GPL 3.0 or any newer version
21  * @link                http://www.ship-simu.org
22  *
23  * This program is free software: you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation, either version 3 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program. If not, see <http://www.gnu.org/licenses/>.
35  */
36 final class StringUtils extends BaseFrameworkSystem {
37         /**
38          * Thousands separator
39          */
40         private static $thousands = ''; // German
41
42         /**
43          * Decimal separator
44          */
45         private static $decimals  = ''; // German
46
47         /**
48          * Array with bitmasks and such for pack/unpack methods to support both
49          * 32-bit and 64-bit systems
50          */
51         private static $packingData = array(
52                 32 => array(
53                         'step'   => 3,
54                         'left'   => 0xffff0000,
55                         'right'  => 0x0000ffff,
56                         'factor' => 16,
57                         'format' => 'II',
58                 ),
59                 64 => array(
60                         'step'   => 7,
61                         'left'   => 0xffffffff00000000,
62                         'right'  => 0x00000000ffffffff,
63                         'factor' => 32,
64                         'format' => 'NN'
65                 )
66         );
67
68         /**
69          * Simple 64-bit check, thanks to "Salman A" from stackoverflow.com:
70          *
71          * The integer size is 4 bytes on 32-bit and 8 bytes on a 64-bit system.
72          */
73         private static $archArrayElement = 0;
74
75         /**
76          * Private constructor, no instance needed. If PHP would have a static initializer ...
77          *
78          * @return      void
79          */
80         private function __construct () {
81                 // Call parent constructor
82                 parent::__construct(__CLASS__);
83
84                 // Is one not set?
85                 if (empty(self::$archArrayElement)) {
86                         // Set array element
87                         self::$archArrayElement = (PHP_INT_SIZE === 8 ? 64 : 32);
88
89                         // Init from configuration
90                         self::$thousands = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('thousands_separator');
91                         self::$decimals = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('decimals_separator');
92                 }
93         }
94
95         /**
96          * Converts dashes to underscores, e.g. useable for configuration entries
97          *
98          * @param       $str    The string with maybe dashes inside
99          * @return      $str    The converted string with no dashed, but underscores
100          * @throws      NullPointerException    If $str is null
101          * @throws      InvalidArgumentException        If $str is empty
102          */
103         public static function convertDashesToUnderscores ($str) {
104                 // Is it null?
105                 if (is_null($str)) {
106                         // Throw NPE
107                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
108                 } elseif (!is_string($str)) {
109                         // Entry is empty
110                         throw new InvalidArgumentException(sprintf('str[]=%s is not a string', gettype($str)), FrameworkConfiguration::EXCEPTION_CONFIG_KEY_IS_EMPTY);
111                 } elseif ((is_string($str)) && (empty($str))) {
112                         // Entry is empty
113                         throw new InvalidArgumentException('str is empty', FrameworkConfiguration::EXCEPTION_CONFIG_KEY_IS_EMPTY);
114                 }
115
116                 // Convert them all
117                 $str = str_replace('-', '_', $str);
118
119                 // Return converted string
120                 return $str;
121         }
122
123         /**
124          * Encodes raw data (almost any type) by "serializing" it and then pack it
125          * into a "binary format".
126          *
127          * @param       $rawData        Raw data (almost any type)
128          * @return      $encoded        Encoded data
129          * @throws      InvalidArgumentException        If $rawData has a non-serializable data type
130          */
131         public static function encodeData ($rawData) {
132                 // Make sure no objects or resources pass through
133                 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: rawData[]=%s - CALLED!', gettype($rawData)));
134                 if (is_object($rawData) || is_resource($rawData)) {
135                         // Not all variable types should be serialized here
136                         throw new InvalidArgumentException(sprintf('rawData[]=%s cannot be serialized.', gettype($rawData)));
137                 }
138
139                 // Init instance
140                 $dummyInstance = new StringUtils();
141
142                 // First "serialize" it (json_encode() is faster than serialize())
143                 $encoded = self::packString(json_encode($rawData));
144
145                 // And return it
146                 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: encoded()=%d - EXIT!', strlen($encoded)));
147                 return $encoded;
148         }
149
150         /**
151          * Converts e.g. a command from URL to a valid class by keeping out bad characters
152          *
153          * @param       $str            The string, what ever it is needs to be converted
154          * @return      $className      Generated class name
155          */
156         public static final function convertToClassName (string $str) {
157                 // Init class name
158                 $className = '';
159
160                 // Convert all dashes in underscores
161                 $str = self::convertDashesToUnderscores($str);
162
163                 // Now use that underscores to get classname parts for hungarian style
164                 foreach (explode('_', $str) as $strPart) {
165                         // Make the class name part lower case and first upper case
166                         $className .= ucfirst(strtolower($strPart));
167                 }
168
169                 // Return class name
170                 return $className;
171         }
172
173         /**
174          * Formats computer generated price values into human-understandable formats
175          * with thousand and decimal separators.
176          *
177          * @param       $value          The in computer format value for a price
178          * @param       $currency       The currency symbol (use HTML-valid characters!)
179          * @param       $decNum         Number of decimals after commata
180          * @return      $price          The for the current language formated price string
181          * @throws      MissingDecimalsThousandsSeparatorException      If decimals or thousands separator is missing
182          */
183         public static function formatCurrency (float $value, string $currency = '&euro;', int $decNum = 2) {
184                 // Init instance
185                 $dummyInstance = new StringUtils();
186
187                 // Reformat the US number
188                 $price = number_format($value, $decNum, self::$decimals, self::$thousands) . $currency;
189
190                 // Return as string...
191                 return $price;
192         }
193
194         /**
195          * Pack a string into a "binary format". Please execuse me that this is
196          * widely undocumented. :-(
197          *
198          * @param       $str            Unpacked string
199          * @return      $packed         Packed string
200          * @todo        Improve documentation
201          */
202         private static function packString (string $str) {
203                 // First compress the string (gzcompress is okay)
204                 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: str=%s - CALLED!', $str));
205                 $str = gzcompress($str);
206
207                 // Init variable
208                 $packed = '';
209
210                 // And start the "encoding" loop
211                 for ($idx = 0; $idx < strlen($str); $idx += self::$packingData[self::$archArrayElement]['step']) {
212                         $big = 0;
213                         for ($i = 0; $i < self::$packingData[self::$archArrayElement]['step']; $i++) {
214                                 $factor = (self::$packingData[self::$archArrayElement]['step'] - 1 - $i);
215
216                                 if (($idx + $i) <= strlen($str)) {
217                                         $ord = ord(substr($str, ($idx + $i), 1));
218
219                                         $add = $ord * pow(256, $factor);
220
221                                         $big += $add;
222
223                                         //print 'idx=' . $idx . ',i=' . $i . ',ord=' . $ord . ',factor=' . $factor . ',add=' . $add . ',big=' . $big . PHP_EOL;
224                                 }
225                         }
226
227                         // Left/right parts (low/high?)
228                         $l = ($big & self::$packingData[self::$archArrayElement]['left']) >>self::$packingData[self::$archArrayElement]['factor'];
229                         $r = $big & self::$packingData[self::$archArrayElement]['right'];
230
231                         // Create chunk
232                         $chunk = str_pad(pack(self::$packingData[self::$archArrayElement]['format'], $l, $r), 8, '0', STR_PAD_LEFT);
233                         //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: big=%d,chunk(%d)=%s', $big, strlen($chunk), md5($chunk)));
234
235                         $packed .= $chunk;
236                 } // END - for
237
238                 // Return it
239                 //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('STRING-UTILS: packed=%s - EXIT!', $packed));
240                 return $packed;
241         }
242
243 }