Open Monograph Press  3.3.0
PKPString.inc.php
1 <?php
2 
18 /*
19  * Perl-compatibile regular expression (PCRE) constants:
20  * These are defined application-wide for consistency
21  */
22 
23 /*
24  * RFC-2396 URIs
25  *
26  * Thanks to the PEAR Validation package (Tomas V.V.Cox <cox@idecnet.com>,
27  * Pierre-Alain Joye <pajoye@php.net>, Amir Mohammad Saied <amir@php.net>)
28  *
29  * Originally published under the "New BSD License"
30  * http://www.opensource.org/licenses/bsd-license.php
31  */
32 define('PCRE_URI', '(?:([a-z][-+.a-z0-9]*):)?' . // Scheme
33  '(?://' .
34  '(?:((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();:\&=+$,])*)@)?' . // User
35  '(?:((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z](?:[a-z0-9]+)?\.?)' . // Hostname
36  '|([0-9]{1,3}(?:\.[0-9]{1,3}){3}))' . // IP Address
37  '(?::([0-9]*))?)' . // Port
38  '((?:/(?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'():@\&=+$,;])*)*/?)?' . // Path
39  '(?:\?([^#]*))?' . // Query String
40  '(?:\#((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();/?:@\&=+$,])*))?'); // Fragment
41 
42 // Two different types of camel case: one for class names and one for method names
43 define ('CAMEL_CASE_HEAD_UP', 0x01);
44 define ('CAMEL_CASE_HEAD_DOWN', 0x02);
45 
46 class PKPString {
51  static function init() {
52  $clientCharset = strtolower_codesafe(Config::getVar('i18n', 'client_charset'));
53 
54  // Check if mbstring is installed
55  if (self::hasMBString() && !defined('ENABLE_MBSTRING')) {
56  // mbstring routines are available
57  define('ENABLE_MBSTRING', true);
58 
59  // Set up required ini settings for mbstring
60  // FIXME Do any other mbstring settings need to be set?
61  mb_internal_encoding($clientCharset);
62  mb_substitute_character('63'); // question mark
63  }
64 
65  // Define modifier to be used in regexp_* routines
66  // FIXME Should non-UTF-8 encodings be supported with mbstring?
67  if (!defined('PCRE_UTF8')) {
68  if ($clientCharset == 'utf-8' && self::hasPCREUTF8()) {
69  define('PCRE_UTF8', 'u');
70  } else {
71  define('PCRE_UTF8', '');
72  }
73  }
74  }
75 
80  static function hasMBString() {
81  static $hasMBString;
82  if (isset($hasMBString)) return $hasMBString;
83 
84  // If string overloading is active, it will break many of the
85  // native implementations. mbstring.func_overload must be set
86  // to 0, 1 or 4 in php.ini (string overloading disabled).
87  if (ini_get('mbstring.func_overload') && defined('MB_OVERLOAD_STRING')) {
88  $hasMBString = false;
89  } else {
90  $hasMBString = (
91  extension_loaded('mbstring') &&
92  function_exists('mb_strlen') &&
93  function_exists('mb_strpos') &&
94  function_exists('mb_strrpos') &&
95  function_exists('mb_substr') &&
96  function_exists('mb_strtolower') &&
97  function_exists('mb_strtoupper') &&
98  function_exists('mb_substr_count') &&
99  function_exists('mb_send_mail')
100  );
101  }
102  return $hasMBString;
103  }
104 
109  static function hasPCREUTF8() {
110  // The PCRE_UTF8 modifier is only supported on PHP >= 4.1.0 (*nix) or PHP >= 4.2.3 (win32)
111  // Evil check to see if PCRE_UTF8 is supported
112  if (@preg_match('//u', '')) {
113  return true;
114  } else {
115  return false;
116  }
117  }
118 
119  //
120  // Wrappers for basic string manipulation routines.
121  //
122 
128  static function strlen($string) {
129  return Stringy\Stringy::create($string)->length();
130  }
131 
139  static function strpos($haystack, $needle, $offset = 0) {
140  return Stringy\Stringy::create($haystack)->indexOf($needle, $offset);
141  }
142 
149  static function strrpos($haystack, $needle) {
150  return Stringy\Stringy::create($haystack)->indexOfLast($needle);
151  }
152 
160  static function substr($string, $start, $length = null) {
161  return (string) Stringy\Stringy::create($string)->substr($start, $length);
162  }
163 
169  static function strtolower($string) {
170  return (string) Stringy\Stringy::create($string)->toLowerCase();
171  }
172 
178  static function strtoupper($string) {
179  return (string) Stringy\Stringy::create($string)->toUpperCase();
180  }
181 
187  static function ucfirst($string) {
188  return (string) Stringy\Stringy::create($string)->upperCaseFirst();
189  }
190 
197  static function substr_count($haystack, $needle) {
198  return Stringy\Stringy::create($haystack)->countSubstring($needle);
199  }
200 
206  static function encode_mime_header($string) {
207  if (defined('ENABLE_MBSTRING')) {
208  return mb_encode_mimeheader($string, mb_internal_encoding(), 'B', MAIL_EOL);
209  } else {
210  return $string;
211  }
212  }
213 
214  //
215  // Wrappers for PCRE-compatible regular expression routines.
216  // See the php.net documentation for usage.
217  //
218 
225  static function regexp_quote($string, $delimiter = '/') {
226  return preg_quote($string, $delimiter);
227  }
228 
235  static function regexp_grep($pattern, $input) {
236  return preg_grep($pattern . PCRE_UTF8, $input);
237  }
238 
245  static function regexp_match($pattern, $subject) {
246  return preg_match($pattern . PCRE_UTF8, $subject);
247  }
248 
256  static function regexp_match_get($pattern, $subject, &$matches) {
257  return preg_match($pattern . PCRE_UTF8, $subject, $matches);
258  }
259 
267  static function regexp_match_all($pattern, $subject, &$matches) {
268  return preg_match_all($pattern . PCRE_UTF8, $subject, $matches);
269  }
270 
279  static function regexp_replace($pattern, $replacement, $subject, $limit = -1) {
280  return preg_replace($pattern . PCRE_UTF8, $replacement, $subject, $limit);
281  }
282 
291  static function regexp_replace_callback($pattern, $callback, $subject, $limit = -1) {
292  return preg_replace_callback($pattern . PCRE_UTF8, $callback, $subject, $limit);
293  }
294 
302  static function regexp_split($pattern, $subject, $limit = -1) {
303  return preg_split($pattern . PCRE_UTF8, $subject, $limit);
304  }
305 
312  static function mime_content_type($filename, $suggestedExtension = '') {
313  $result = null;
314 
315  if (function_exists('finfo_open')) {
316  $fi =& Registry::get('fileInfo', true, null);
317  if ($fi === null) {
318  $fi = finfo_open(FILEINFO_MIME, Config::getVar('finfo', 'mime_database_path'));
319  }
320  if ($fi !== false) {
321  $result = strtok(finfo_file($fi, $filename), ' ;');
322  }
323  }
324 
325  if (!$result && function_exists('mime_content_type')) {
326  $result = mime_content_type($filename);
327  // mime_content_type appears to return a charset
328  // (erroneously?) in recent versions of PHP5
329  if (($i = strpos($result, ';')) !== false) {
330  $result = trim(substr($result, 0, $i));
331  }
332  }
333 
334  if (!$result) {
335  // Fall back on an external "file" tool
336  $f = escapeshellarg($filename);
337  $result = trim(`file --brief --mime $f`);
338  // Make sure we just return the mime type.
339  if (($i = strpos($result, ';')) !== false) {
340  $result = trim(substr($result, 0, $i));
341  }
342  }
343 
344  // Check ambiguous mimetypes against extension
345  $exploded = explode('.',$filename);
346  $ext = array_pop($exploded);
347  if ($suggestedExtension) {
348  $ext = $suggestedExtension;
349  }
350  // SUGGESTED_EXTENSION:DETECTED_MIME_TYPE => OVERRIDE_MIME_TYPE
351  $ambiguities = array(
352  'html:text/xml' => 'text/html',
353  'css:text/x-c' => 'text/css',
354  'css:text/plain' => 'text/css',
355  'xlsx:application/zip' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
356  'xltx:application/zip' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
357  'potx:application/zip' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
358  'ppsx:application/zip' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
359  'pptx:application/zip' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
360  'sldx:application/zip' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
361  'docx:application/zip' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
362  'dotx:application/zip' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
363  );
364  if (isset($ambiguities[strtolower($ext.':'.$result)])) {
365  $result = $ambiguities[strtolower($ext.':'.$result)];
366  }
367 
368  return $result;
369  }
370 
377  static function stripUnsafeHtml($input) {
378  static $purifier;
379  if (!isset($purifier)) {
380  $config = HTMLPurifier_Config::createDefault();
381  $config->set('Core.Encoding', Config::getVar('i18n', 'client_charset'));
382  $config->set('HTML.Doctype', 'HTML 4.01 Transitional');
383  $config->set('HTML.Allowed', Config::getVar('security', 'allowed_html'));
384  $config->set('Cache.SerializerPath', 'cache');
385  $purifier = new HTMLPurifier($config);
386  }
387  return $purifier->purify($input);
388  }
389 
395  static function html2text($html) {
396  $html = self::regexp_replace('/<[\/]?p>/', "\n", $html);
397  $html = self::regexp_replace('/<li>/', '&bull; ', $html);
398  $html = self::regexp_replace('/<\/li>/', "\n", $html);
399  $html = self::regexp_replace('/<br[ ]?[\/]?>/', "\n", $html);
400  $html = html_entity_decode(strip_tags($html), ENT_COMPAT, 'UTF-8');
401  return $html;
402  }
403 
410  static function concatTitleFields($fields) {
411  // Set the characters that will avoid the use of
412  // a semicolon between title and subtitle.
413  $avoidColonChars = array('?', '!', '/', '&');
414 
415  // if the first field ends in a character in $avoidColonChars,
416  // concat with a space, otherwise use a colon.
417  // Check for any of these characters in
418  // the last position of current full title value.
419  if (in_array(substr($fields[0], -1, 1), $avoidColonChars)) {
420  $fullTitle = join(' ', $fields);
421  } else {
422  $fullTitle = join(': ', $fields);
423  }
424 
425  return $fullTitle;
426  }
427 
435  static function camelize($string, $type = CAMEL_CASE_HEAD_UP) {
436  assert($type == CAMEL_CASE_HEAD_UP || $type == CAMEL_CASE_HEAD_DOWN);
437 
438  // Transform "handler-class" to "HandlerClass" and "my-op" to "MyOp"
439  $string = implode(array_map('ucfirst_codesafe', explode('-', $string)));
440 
441  // Transform "MyOp" to "myOp"
442  if ($type == CAMEL_CASE_HEAD_DOWN) {
443  $string = strtolower_codesafe(substr($string, 0, 1)).substr($string, 1);
444  }
445 
446  return $string;
447  }
448 
455  static function uncamelize($string) {
456  assert(!empty($string));
457 
458  // Transform "myOp" to "MyOp"
459  $string = ucfirst_codesafe($string);
460 
461  // Insert hyphens between words and return the string in lowercase
462  $words = array();
463  self::regexp_match_all('/[A-Z][a-z0-9]*/', $string, $words);
464  assert(isset($words[0]) && !empty($words[0]) && strlen(implode('', $words[0])) == strlen($string));
465  return strtolower_codesafe(implode('-', $words[0]));
466  }
467 
473  static function enumerateAlphabetically($steps) {
474  return chr(ord('A') + $steps);
475  }
476 
481  static function generateUUID() {
482  mt_srand((double)microtime()*10000);
483  $charid = strtoupper(md5(uniqid(rand(), true)));
484  $hyphen = '-';
485  $uuid = substr($charid, 0, 8).$hyphen
486  .substr($charid, 8, 4).$hyphen
487  .'4'.substr($charid,13, 3).$hyphen
488  .strtoupper(dechex(hexdec(ord(substr($charid,16,1))) % 4 + 8)).substr($charid,17, 3).$hyphen
489  .substr($charid,20,12);
490  return $uuid;
491  }
492 
499  static function dateformatPHP2JQueryDatepicker($phpFormat) {
500  $symbols = array(
501  // Day
502  'a' => 'D', // date() format 'D'
503  'A' => 'DD', // date() format 'DD'
504  'd' => 'dd', // date() format 'd'
505  'e' => 'd', // date() format 'j'
506  'j' => 'oo', // date() format none
507  'u' => '', // date() format 'N'
508  'w' => '', // date() format 'w'
509 
510  // Week
511  'U' => '', // date() format none
512  'V' => '', // date() format none
513  'W' => '', // date() format 'W'
514 
515  // Month
516  'b' => 'M', // date() format 'M'
517  'h' => 'M', // date() format 'M'
518  'B' => 'MM', // date() format 'F'
519  'm' => 'mm', // date() format 'm'
520 
521  // Year
522  'C' => '', // date() format none
523  'g' => 'y', // date() format none
524  'G' => 'yy', // date() format 'o'
525  'y' => 'y', // date() format 'y'
526  'Y' => 'yy', // date() format 'Y'
527 
528  // Time
529  'H' => '', // date() format 'H'
530  'k' => '', // date() format none
531  'I' => '', // date() format 'h'
532  'l' => '', // date() format 'g'
533  'P' => '', // date() format 'a'
534  'p' => '', // date() format 'A'
535  'M' => '', // date() format 'i'
536  'S' => '', // date() format 's'
537  's' => '', // date() format 'u'
538 
539  // Timezone
540  'z' => '', // date() format 'O'
541  'Z' => '', // date() format 'T'
542 
543  // Full Date/Time
544  'r' => '', // date() format none
545  'R' => '', // date() format none
546  'X' => '', // date() format none
547  'D' => '', // date() format none
548  'F' => '', // date() format none
549  'x' => '', // date() format none
550  'c' => '', // date() format none
551 
552  // Other
553  '%' => ''
554  );
555 
556  $datepickerFormat = "";
557  $escaping = false;
558 
559  for ($i = 0; $i < strlen($phpFormat); $i++) {
560  $char = $phpFormat[$i];
561  if($char === '\\') {
562  $i++;
563  $datepickerFormat .= $escaping ? $phpFormat[$i] : '\'' . $phpFormat[$i];
564 
565  $escaping = true;
566  } else {
567  if($escaping) {
568  $datepickerFormat .= "'";
569  $escaping = false;
570  }
571 
572  $datepickerFormat .= isset($symbols[$char]) ? $symbols[$char] : $char;
573 
574  }
575  }
576 
577  return $datepickerFormat;
578  }
579 }
PKPString
String manipulation wrapper class.
Definition: PKPString.inc.php:46
PKPString\regexp_quote
static regexp_quote($string, $delimiter='/')
Definition: PKPString.inc.php:225
PKPString\init
static init()
Definition: PKPString.inc.php:51
PKPString\substr_count
static substr_count($haystack, $needle)
Definition: PKPString.inc.php:197
PKPString\regexp_match_get
static regexp_match_get($pattern, $subject, &$matches)
Definition: PKPString.inc.php:256
PKPString\strrpos
static strrpos($haystack, $needle)
Definition: PKPString.inc.php:149
PKPString\hasPCREUTF8
static hasPCREUTF8()
Definition: PKPString.inc.php:109
PKPString\regexp_replace
static regexp_replace($pattern, $replacement, $subject, $limit=-1)
Definition: PKPString.inc.php:279
PKPString\stripUnsafeHtml
static stripUnsafeHtml($input)
Definition: PKPString.inc.php:377
PKPString\ucfirst
static ucfirst($string)
Definition: PKPString.inc.php:187
PKPString\regexp_grep
static regexp_grep($pattern, $input)
Definition: PKPString.inc.php:235
PKPString\regexp_match_all
static regexp_match_all($pattern, $subject, &$matches)
Definition: PKPString.inc.php:267
PKPString\substr
static substr($string, $start, $length=null)
Definition: PKPString.inc.php:160
PKPString\regexp_split
static regexp_split($pattern, $subject, $limit=-1)
Definition: PKPString.inc.php:302
PKPString\uncamelize
static uncamelize($string)
Definition: PKPString.inc.php:455
PKPString\concatTitleFields
static concatTitleFields($fields)
Definition: PKPString.inc.php:410
PKPString\strlen
static strlen($string)
Definition: PKPString.inc.php:128
PKPString\strtoupper
static strtoupper($string)
Definition: PKPString.inc.php:178
PKPString\html2text
static html2text($html)
Definition: PKPString.inc.php:395
PKPString\dateformatPHP2JQueryDatepicker
static dateformatPHP2JQueryDatepicker($phpFormat)
Definition: PKPString.inc.php:499
Registry\get
static & get($key, $createIfEmpty=false, $createWithDefault=null)
Definition: Registry.inc.php:35
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
ucfirst_codesafe
ucfirst_codesafe($str)
Definition: functions.inc.php:310
PKPString\hasMBString
static hasMBString()
Definition: PKPString.inc.php:80
PKPString\mime_content_type
static mime_content_type($filename, $suggestedExtension='')
Definition: PKPString.inc.php:312
PKPString\regexp_replace_callback
static regexp_replace_callback($pattern, $callback, $subject, $limit=-1)
Definition: PKPString.inc.php:291
strtolower_codesafe
strtolower_codesafe($str)
Definition: functions.inc.php:280
PKPString\strtolower
static strtolower($string)
Definition: PKPString.inc.php:169
PKPString\generateUUID
static generateUUID()
Definition: PKPString.inc.php:481
PKPString\camelize
static camelize($string, $type=CAMEL_CASE_HEAD_UP)
Definition: PKPString.inc.php:435
PKPString\encode_mime_header
static encode_mime_header($string)
Definition: PKPString.inc.php:206
PKPString\regexp_match
static regexp_match($pattern, $subject)
Definition: PKPString.inc.php:245
PKPString\strpos
static strpos($haystack, $needle, $offset=0)
Definition: PKPString.inc.php:139
PKPString\enumerateAlphabetically
static enumerateAlphabetically($steps)
Definition: PKPString.inc.php:473