1 : <?php
2 : /**
3 : * Licensed to the Apache Software Foundation (ASF) under one or more
4 : * contributor license agreements. See the NOTICE file distributed with
5 : * this work for additional information regarding copyright ownership.
6 : * The ASF licenses this file to You under the Apache License, Version 2.0
7 : * (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : *
18 : * @package log4php
19 : */
20 :
21 : /**
22 : * A convenience class to convert property values to specific types.
23 : *
24 : * @version $Revision: 1237446 $
25 : * @package log4php
26 : * @subpackage helpers
27 : * @since 0.5
28 : */
29 : class LoggerOptionConverter {
30 :
31 : const DELIM_START = '${';
32 : const DELIM_STOP = '}';
33 : const DELIM_START_LEN = 2;
34 : const DELIM_STOP_LEN = 1;
35 :
36 : /** String values which are converted to boolean TRUE. */
37 : private static $trueValues = array('1', 'true', 'yes', 'on');
38 :
39 : /**
40 : * String values which are converted to boolean FALSE.
41 : *
42 : * Note that an empty string must convert to false, because
43 : * parse_ini_file() which is used for parsing configuration
44 : * converts the value _false_ to an empty string.
45 : */
46 : private static $falseValues = array('0', 'false', 'no', 'off', '');
47 :
48 : /**
49 : * Read a predefined var.
50 : *
51 : * It returns a value referenced by <var>$key</var> using this search criteria:
52 : * - if <var>$key</var> is a constant then return it. Else
53 : * - if <var>$key</var> is set in <var>$_ENV</var> then return it. Else
54 : * - return <var>$def</var>.
55 : *
56 : * @param string $key The key to search for.
57 : * @param string $def The default value to return.
58 : * @return string the string value of the system property, or the default
59 : * value if there is no property with that key.
60 : */
61 : public static function getSystemProperty($key, $def) {
62 1 : if(defined($key)) {
63 1 : return (string)constant($key);
64 1 : } else if(isset($_SERVER[$key])) {
65 0 : return (string)$_SERVER[$key];
66 1 : } else if(isset($_ENV[$key])) {
67 0 : return (string)$_ENV[$key];
68 : } else {
69 1 : return $def;
70 : }
71 : }
72 :
73 : /**
74 : * If <var>$value</var> is <i>true</i>, then <i>true</i> is
75 : * returned. If <var>$value</var> is <i>false</i>, then
76 : * <i>true</i> is returned. Otherwise, <var>$default</var> is
77 : * returned.
78 : *
79 : * <p>Case of value is unimportant.</p>
80 : *
81 : * @param string $value
82 : * @param boolean $default
83 : * @return boolean
84 : */
85 : public static function toBoolean($value, $default=true) {
86 6 : if (is_null($value)) {
87 1 : return $default;
88 6 : } elseif (is_string($value)) {
89 5 : $trimmedVal = strtolower(trim($value));
90 5 : if("1" == $trimmedVal or "true" == $trimmedVal or "yes" == $trimmedVal or "on" == $trimmedVal) {
91 1 : return true;
92 5 : } else if ("" == $trimmedVal or "0" == $trimmedVal or "false" == $trimmedVal or "no" == $trimmedVal or "off" == $trimmedVal) {
93 4 : return false;
94 : }
95 3 : } elseif (is_bool($value)) {
96 2 : return $value;
97 1 : } elseif (is_int($value)) {
98 1 : return !($value == 0); // true is everything but 0 like in C
99 : }
100 :
101 2 : return $default;
102 : }
103 :
104 : /** Converts $value to boolean, or throws an exception if not possible. */
105 : public static function toBooleanEx($value) {
106 27 : if (isset($value)) {
107 26 : if (is_bool($value)) {
108 15 : return $value;
109 : }
110 12 : $value = strtolower(trim($value));
111 12 : if (in_array($value, self::$trueValues)) {
112 5 : return true;
113 : }
114 9 : if (in_array($value, self::$falseValues)) {
115 7 : return false;
116 : }
117 2 : }
118 :
119 3 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to boolean.");
120 : }
121 :
122 : /**
123 : * @param string $value
124 : * @param integer $default
125 : * @return integer
126 : */
127 : public static function toInt($value, $default) {
128 1 : $value = trim($value);
129 1 : if(is_numeric($value)) {
130 1 : return (int)$value;
131 : } else {
132 1 : return $default;
133 : }
134 : }
135 :
136 :
137 : /**
138 : * Converts $value to integer, or throws an exception if not possible.
139 : * Floats cannot be converted to integer.
140 : */
141 : public static function toIntegerEx($value) {
142 6 : if (is_integer($value)) {
143 1 : return $value;
144 : }
145 6 : if (is_numeric($value) && ($value == (integer) $value)) {
146 1 : return (integer) $value;
147 : }
148 :
149 5 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to integer.");
150 : }
151 :
152 : /**
153 : * Converts $value to integer, or throws an exception if not possible.
154 : * Floats cannot be converted to integer.
155 : */
156 : public static function toPositiveIntegerEx($value) {
157 4 : if (is_integer($value) && $value > 0) {
158 4 : return $value;
159 : }
160 0 : if (is_numeric($value) && ($value == (integer) $value) && $value > 0) {
161 0 : return (integer) $value;
162 : }
163 :
164 0 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a positive integer.");
165 : }
166 :
167 : /**
168 : * Converts a standard or custom priority level to a Level
169 : * object.
170 : *
171 : * <p> If <var>$value</var> is of form "<b>level#full_file_classname</b>",
172 : * where <i>full_file_classname</i> means the class filename with path
173 : * but without php extension, then the specified class' <i>toLevel()</i> method
174 : * is called to process the specified level string; if no '#'
175 : * character is present, then the default {@link LoggerLevel}
176 : * class is used to process the level value.</p>
177 : *
178 : * <p>As a special case, if the <var>$value</var> parameter is
179 : * equal to the string "NULL", then the value <i>null</i> will
180 : * be returned.</p>
181 : *
182 : * <p>If any error occurs while converting the value to a level,
183 : * the <var>$defaultValue</var> parameter, which may be
184 : * <i>null</i>, is returned.</p>
185 : *
186 : * <p>Case of <var>$value</var> is insignificant for the level level, but is
187 : * significant for the class name part, if present.</p>
188 : *
189 : * @param string $value
190 : * @param LoggerLevel $defaultValue
191 : * @return LoggerLevel a {@link LoggerLevel} or null
192 : */
193 : public static function toLevel($value, $defaultValue) {
194 0 : if($value === null) {
195 0 : return $defaultValue;
196 : }
197 0 : $hashIndex = strpos($value, '#');
198 0 : if($hashIndex === false) {
199 0 : if("NULL" == strtoupper($value)) {
200 0 : return null;
201 : } else {
202 : // no class name specified : use standard Level class
203 0 : return LoggerLevel::toLevel($value, $defaultValue);
204 : }
205 : }
206 :
207 0 : $result = $defaultValue;
208 :
209 0 : $clazz = substr($value, ($hashIndex + 1));
210 0 : $levelName = substr($value, 0, $hashIndex);
211 :
212 : // This is degenerate case but you never know.
213 0 : if("NULL" == strtoupper($levelName)) {
214 0 : return null;
215 : }
216 :
217 0 : $clazz = basename($clazz);
218 :
219 0 : if(class_exists($clazz)) {
220 0 : $result = @call_user_func(array($clazz, 'toLevel'), $levelName, $defaultValue);
221 0 : if(!$result instanceof LoggerLevel) {
222 0 : $result = $defaultValue;
223 0 : }
224 0 : }
225 0 : return $result;
226 : }
227 :
228 :
229 : /** Converts the value to a level. Throws an exception if not possible. */
230 : public static function toLevelEx($value) {
231 15 : if ($value instanceof LoggerLevel) {
232 12 : return $value;
233 : }
234 3 : $level = LoggerLevel::toLevel($value);
235 3 : if ($level === null) {
236 0 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a logger level.");
237 : }
238 3 : return $level;
239 : }
240 :
241 : /**
242 : * @param string $value
243 : * @param float $default
244 : * @return float
245 : */
246 : public static function toFileSize($value, $default) {
247 0 : if($value === null) {
248 0 : return $default;
249 : }
250 :
251 0 : $s = strtoupper(trim($value));
252 0 : $multiplier = (float)1;
253 0 : if(($index = strpos($s, 'KB')) !== false) {
254 0 : $multiplier = 1024;
255 0 : $s = substr($s, 0, $index);
256 0 : } else if(($index = strpos($s, 'MB')) !== false) {
257 0 : $multiplier = 1024 * 1024;
258 0 : $s = substr($s, 0, $index);
259 0 : } else if(($index = strpos($s, 'GB')) !== false) {
260 0 : $multiplier = 1024 * 1024 * 1024;
261 0 : $s = substr($s, 0, $index);
262 0 : }
263 0 : if(is_numeric($s)) {
264 0 : return (float)$s * $multiplier;
265 : }
266 0 : return $default;
267 : }
268 :
269 :
270 : /**
271 : * Converts a value to a valid file size (integer).
272 : *
273 : * Supports 'KB', 'MB' and 'GB' suffixes, where KB = 1024 B etc.
274 : *
275 : * The final value will be rounded to the nearest integer.
276 : *
277 : * Examples:
278 : * - '100' => 100
279 : * - '100.12' => 100
280 : * - '100KB' => 102400
281 : * - '1.5MB' => 1572864
282 : *
283 : * @param mixed $value File size (optionally with suffix).
284 : * @return integer Parsed file size.
285 : */
286 : public static function toFileSizeEx($value) {
287 :
288 3 : if (empty($value)) {
289 0 : throw new LoggerException("Empty value cannot be converted to a file size.");
290 : }
291 :
292 3 : if (is_numeric($value)) {
293 1 : return (integer) $value;
294 : }
295 :
296 3 : if (!is_string($value)) {
297 0 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to a file size.");
298 : }
299 :
300 3 : $str = strtoupper(trim($value));
301 3 : $count = preg_match('/^([0-9.]+)(KB|MB|GB)?$/', $str, $matches);
302 :
303 3 : if ($count > 0) {
304 3 : $size = $matches[1];
305 3 : $unit = $matches[2];
306 :
307 : switch($unit) {
308 3 : case 'KB': $size *= pow(1024, 1); break;
309 1 : case 'MB': $size *= pow(1024, 2); break;
310 1 : case 'GB': $size *= pow(1024, 3); break;
311 : }
312 :
313 3 : return (integer) $size;
314 : }
315 :
316 0 : throw new LoggerException("Given value [$value] cannot be converted to a file size.");
317 : }
318 :
319 : /**
320 : * Converts a value to string, or throws an exception if not possible.
321 : *
322 : * Objects can be converted to string if they implement the magic
323 : * __toString() method.
324 : *
325 : */
326 : public static function toStringEx($value) {
327 24 : if (is_string($value)) {
328 24 : return $value;
329 : }
330 0 : if (is_numeric($value)) {
331 0 : return (string) $value;
332 : }
333 0 : if (is_object($value) && method_exists($value, '__toString')) {
334 0 : return (string) $value;
335 : }
336 :
337 0 : throw new LoggerException("Given value [" . var_export($value, true) . "] cannot be converted to string.");
338 : }
339 :
340 :
341 : /**
342 : * Find the value corresponding to <var>$key</var> in
343 : * <var>$props</var>. Then perform variable substitution on the
344 : * found value.
345 : *
346 : * @param string $key
347 : * @param array $props
348 : * @return string
349 : */
350 : public static function findAndSubst($key, $props) {
351 2 : $value = @$props[$key];
352 :
353 : // If coming from the LoggerConfiguratorIni, some options were
354 : // already mangled by parse_ini_file:
355 : //
356 : // not specified => never reaches this code
357 : // ""|off|false|null => string(0) ""
358 : // "1"|on|true => string(1) "1"
359 : // "true" => string(4) "true"
360 : // "false" => string(5) "false"
361 : //
362 : // As the integer 1 and the boolean true are therefore indistinguable
363 : // it's up to the setter how to deal with it, they can not be cast
364 : // into a boolean here. {@see toBoolean}
365 : // Even an empty value has to be given to the setter as it has been
366 : // explicitly set by the user and is different from an option which
367 : // has not been specified and therefore keeps its default value.
368 : //
369 : // if(!empty($value)) {
370 2 : return LoggerOptionConverter::substVars($value, $props);
371 : // }
372 : }
373 :
374 : /**
375 : * Perform variable substitution in string <var>$val</var> from the
376 : * values of keys found with the {@link getSystemProperty()} method.
377 : *
378 : * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
379 : *
380 : * <p>For example, if the "MY_CONSTANT" contains "value", then
381 : * the call
382 : * <code>
383 : * $s = LoggerOptionConverter::substVars("Value of key is ${MY_CONSTANT}.");
384 : * </code>
385 : * will set the variable <i>$s</i> to "Value of key is value.".</p>
386 : *
387 : * <p>If no value could be found for the specified key, then the
388 : * <var>$props</var> parameter is searched, if the value could not
389 : * be found there, then substitution defaults to the empty string.</p>
390 : *
391 : * <p>For example, if {@link getSystemProperty()} cannot find any value for the key
392 : * "inexistentKey", then the call
393 : * <code>
394 : * $s = LoggerOptionConverter::substVars("Value of inexistentKey is [${inexistentKey}]");
395 : * </code>
396 : * will set <var>$s</var> to "Value of inexistentKey is []".</p>
397 : *
398 : * <p>A warn is thrown if <var>$val</var> contains a start delimeter "${"
399 : * which is not balanced by a stop delimeter "}" and an empty string is returned.</p>
400 : *
401 : * @param string $val The string on which variable substitution is performed.
402 : * @param array $props
403 : * @return string
404 : */
405 : // TODO: this method doesn't work correctly with key = true, it needs key = "true" which is odd
406 : public static function substVars($val, $props = null) {
407 3 : $sbuf = '';
408 3 : $i = 0;
409 3 : while(true) {
410 3 : $j = strpos($val, self::DELIM_START, $i);
411 3 : if($j === false) {
412 : // no more variables
413 3 : if($i == 0) { // this is a simple string
414 3 : return $val;
415 : } else { // add the tail string which contails no variables and return the result.
416 1 : $sbuf .= substr($val, $i);
417 1 : return $sbuf;
418 : }
419 : } else {
420 :
421 1 : $sbuf .= substr($val, $i, $j-$i);
422 1 : $k = strpos($val, self::DELIM_STOP, $j);
423 1 : if($k === false) {
424 : // LoggerOptionConverter::substVars() has no closing brace. Opening brace
425 0 : return '';
426 : } else {
427 1 : $j += self::DELIM_START_LEN;
428 1 : $key = substr($val, $j, $k - $j);
429 : // first try in System properties
430 1 : $replacement = LoggerOptionConverter::getSystemProperty($key, null);
431 : // then try props parameter
432 1 : if($replacement == null and $props !== null) {
433 1 : $replacement = @$props[$key];
434 1 : }
435 :
436 1 : if(!empty($replacement)) {
437 : // Do variable substitution on the replacement string
438 : // such that we can solve "Hello ${x2}" as "Hello p1"
439 : // the where the properties are
440 : // x1=p1
441 : // x2=${x1}
442 1 : $recursiveReplacement = LoggerOptionConverter::substVars($replacement, $props);
443 1 : $sbuf .= $recursiveReplacement;
444 1 : }
445 1 : $i = $k + self::DELIM_STOP_LEN;
446 : }
447 : }
448 1 : }
449 0 : }
450 :
451 : }
|