1 <?php
  2 
  3 /**
  4  * String formatter class.
  5  *
  6  * @package redaxo\core
  7  */
  8 abstract class rex_formatter
  9 {
 10     /**
 11      * It's not allowed to create instances of this class.
 12      */
 13     private function __construct()
 14     {
 15     }
 16 
 17     /**
 18      * Formats a string by the given format type.
 19      *
 20      * @param string $value      Value
 21      * @param string $formatType Format type (any method name of this class)
 22      * @param mixed  $format     For possible values look at the other methods of this class
 23      *
 24      * @return string
 25      *
 26      * @throws InvalidArgumentException
 27      */
 28     public static function format($value, $formatType, $format)
 29     {
 30         if (!is_callable([self::class, $formatType])) {
 31             throw new InvalidArgumentException('Unknown $formatType: "' . $formatType . '"!');
 32         }
 33         return self::$formatType($value, $format);
 34     }
 35 
 36     /**
 37      * Formats a string by `date()`.
 38      *
 39      * @see http://www.php.net/manual/en/function.date.php
 40      *
 41      * @param string $value  Unix timestamp or datetime string for `strtotime`
 42      * @param string $format Default format is `d.m.Y`
 43      *
 44      * @return string
 45      */
 46     public static function date($value, $format = '')
 47     {
 48         if (empty($value)) {
 49             return '';
 50         }
 51 
 52         if ($format == '') {
 53             $format = 'd.m.Y';
 54         }
 55 
 56         return date($format, self::getTimestamp($value));
 57     }
 58 
 59     /**
 60      * Formats a string by `strftime()`.
 61      *
 62      * @see http://www.php.net/manual/en/function.strftime.php
 63      *
 64      * @param string $value  Unix timestamp or datetime string for `strtotime`
 65      * @param string $format Possible values are format strings like in `strftime` or "date" or "datetime", default is "date"
 66      *
 67      * @return string
 68      */
 69     public static function strftime($value, $format = '')
 70     {
 71         if (empty($value)) {
 72             return '';
 73         }
 74 
 75         if ($format == '' || $format == 'date') {
 76             // Default REX-Dateformat
 77             $format = rex_i18n::msg('dateformat');
 78         } elseif ($format == 'datetime') {
 79             // Default REX-Datetimeformat
 80             $format = rex_i18n::msg('datetimeformat');
 81         } elseif ($format == 'time') {
 82             // Default REX-Timeformat
 83             $format = rex_i18n::msg('timeformat');
 84         }
 85         return strftime($format, self::getTimestamp($value));
 86     }
 87 
 88     /**
 89      * Formats a string by `number_format()`.
 90      *
 91      * @see http://www.php.net/manual/en/function.number-format.php
 92      *
 93      * @param string $value  Value
 94      * @param array  $format Array with number of decimals, decimals point and thousands separator, default is `array(2, ',', ' ')`
 95      *
 96      * @return string
 97      */
 98     public static function number($value, $format = [])
 99     {
100         if (!is_array($format)) {
101             $format = [];
102         }
103 
104         // Kommastellen
105         if (!isset($format[0])) {
106             $format[0] = 2;
107         }
108         // Dezimal Trennzeichen
109         if (!isset($format[1])) {
110             $format[1] = ',';
111         }
112         // Tausender Trennzeichen
113         if (!isset($format[2])) {
114             $format[2] = ' ';
115         }
116         return number_format($value, $format[0], $format[1], $format[2]);
117     }
118 
119     /**
120      * Formats a string as bytes.
121      *
122      * @param string $value  Value
123      * @param array  $format Same as {@link rex_formatter::number()}
124      *
125      * @return string
126      */
127     public static function bytes($value, $format = [])
128     {
129         $units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
130         $unit_index = 0;
131         while (($value / 1024) >= 1) {
132             $value /= 1024;
133             ++$unit_index;
134         }
135 
136         if (isset($format[0])) {
137             $z = (int) ($value * pow(10, $precision = (int) ($format[0])));
138             for ($i = 0; $i < (int) $precision; ++$i) {
139                 if (($z % 10) == 0) {
140                     $format[0] = (int) ($format[0]) - 1;
141                     $z = (int) ($z / 10);
142                 } else {
143                     break;
144                 }
145             }
146         }
147 
148         return self::number($value, $format) . ' ' . $units[$unit_index];
149     }
150 
151     /**
152      * Formats a string by `sprintf()`.
153      *
154      * @see http://www.php.net/manual/en/function.sprintf.php
155      *
156      * @param string $value  Value
157      * @param string $format
158      *
159      * @return string
160      */
161     public static function sprintf($value, $format = '')
162     {
163         if ($format == '') {
164             $format = '%s';
165         }
166         return sprintf($format, $value);
167     }
168 
169     /**
170      * Formats a string by `nl2br`.
171      *
172      * @see http://www.php.net/manual/en/function.nl2br.php
173      *
174      * @param string $value Value
175      *
176      * @return string
177      */
178     public static function nl2br($value)
179     {
180         return nl2br($value);
181     }
182 
183     /**
184      * Truncates a string.
185      *
186      * @param string $value  Value
187      * @param array  $format Default format is `array('length' => 80, 'etc' => '...', 'break_words' => false)`
188      *
189      * @return string
190      */
191     public static function truncate($value, $format = [])
192     {
193         if (!is_array($format)) {
194             $format = [];
195         }
196 
197         // Max-String-laenge
198         if (empty($format['length'])) {
199             $format['length'] = 80;
200         }
201 
202         // ETC
203         if (empty($format['etc'])) {
204             $format['etc'] = '...';
205         }
206 
207         // Break-Words?
208         if (empty($format['break_words'])) {
209             $format['break_words'] = false;
210         }
211 
212         if (mb_strlen($value) > $format['length']) {
213             $format['length'] -= mb_strlen($format['etc']);
214             if (!$format['break_words']) {
215                 $value = preg_replace('/\s+?(\S+)?$/', '', substr($value, 0, $format['length'] + 1));
216             }
217 
218             return substr($value, 0, $format['length']) . $format['etc'];
219         }
220 
221         return $value;
222     }
223 
224     /**
225      * Avoid widows in a string.
226      *
227      * @param string $value
228      *
229      * @return string
230      */
231     public static function widont($value)
232     {
233         // Sollte ein Wort allein auf einer Zeile vorkommen, wird dies unterbunden
234         $value = rtrim($value);
235         $space = strrpos($value, ' ');
236         if ($space !== false) {
237             $value = substr($value, 0, $space) . '&#160;' . substr($value, $space + 1);
238         }
239         return $value;
240     }
241 
242     /**
243      * Formats a version string by `sprintf()`.
244      *
245      * @see http://www.php.net/manual/en/function.sprintf.php
246      *
247      * @param string $value  Version
248      * @param string $format Version format, e.g. "%s.%s"
249      *
250      * @return string
251      */
252     public static function version($value, $format)
253     {
254         return vsprintf($format, rex_string::versionSplit($value));
255     }
256 
257     /**
258      * Formats a string as link.
259      *
260      * @param string $value  URL
261      * @param array  $format Array with link attributes and params
262      *
263      * @return string Link
264      */
265     public static function url($value, $format = [])
266     {
267         if (empty($value)) {
268             return '';
269         }
270 
271         if (!is_array($format)) {
272             $format = [];
273         }
274 
275         // Linkattribute
276         if (empty($format['attr'])) {
277             $format['attr'] = '';
278         }
279         // Linkparameter (z.b. subject=Hallo Sir)
280         if (empty($format['params'])) {
281             $format['params'] = '';
282         } else {
283             if (strstr($format['params'], '?') != $format['params']) {
284                 $format['params'] = '?' . $format['params'];
285             }
286         }
287         // Protokoll
288         if (!preg_match('@((ht|f)tps?|telnet|redaxo)://@', $value)) {
289             $value = 'http://' . $value;
290         }
291 
292         return '<a href="' . rex_escape($value . $format['params']) . '"' . $format['attr'] . '>' . rex_escape($value) . '</a>';
293     }
294 
295     /**
296      * Formats a string as email link.
297      *
298      * @param string $value  Email
299      * @param array  $format Array with link attributes and params
300      *
301      * @return string Email link
302      */
303     public static function email($value, $format = [])
304     {
305         if (!is_array($format)) {
306             $format = [];
307         }
308 
309         // Linkattribute
310         if (empty($format['attr'])) {
311             $format['attr'] = '';
312         }
313         // Linkparameter (z.b. subject=Hallo Sir)
314         if (empty($format['params'])) {
315             $format['params'] = '';
316         } else {
317             if (strstr($format['params'], '?') != $format['params']) {
318                 $format['params'] = '?' . $format['params'];
319             }
320         }
321         // Url formatierung
322         return '<a href="mailto:' . rex_escape($value . $format['params']) . '"' . $format['attr'] . '>' . rex_escape($value) . '</a>';
323     }
324 
325     /**
326      * Formats a string by a custom callable.
327      *
328      * @param string         $value  Value
329      * @param callable|array $format A callable or an array of a callable and additional params
330      *
331      * @return string
332      *
333      * @throws rex_exception
334      */
335     public static function custom($value, $format)
336     {
337         if (!is_callable($format)) {
338             if (!is_callable($format[0])) {
339                 throw new rex_exception('Unable to find callable ' . $format[0] . ' for custom format!');
340             }
341 
342             $params = [];
343             $params['subject'] = $value;
344             if (is_array($format[1])) {
345                 $params = array_merge($format[1], $params);
346             } else {
347                 $params['params'] = $format[1];
348             }
349             // $format ist in der Form
350             // array(Name des Callables, Weitere Parameter)
351             return call_user_func($format[0], $params);
352         }
353 
354         return call_user_func($format, $value);
355     }
356 
357     private static function getTimestamp($value)
358     {
359         if (is_numeric($value)) {
360             return $value;
361         }
362 
363         return strtotime($value);
364     }
365 }
366