Source for file strings.php

Documentation is available at strings.php

  1. <?php
  2.  
  3. /**
  4.  * strings.php
  5.  *
  6.  * This code provides various string manipulation functions that are
  7.  * used by the rest of the SquirrelMail code.
  8.  *
  9.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  10.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  11.  * @version $Id: strings.php,v 1.184.2.58 2006/08/11 11:24:05 kink Exp $
  12.  * @package squirrelmail
  13.  */
  14.  
  15. /**
  16.  * SquirrelMail version number -- DO NOT CHANGE
  17.  */
  18. global $version;
  19. $version '1.4.9 [CVS]';
  20.  
  21. /**
  22.  * SquirrelMail internal version number -- DO NOT CHANGE
  23.  * $sm_internal_version = array (release, major, minor)
  24.  */
  25. global $SQM_INTERNAL_VERSION;
  26. $SQM_INTERNAL_VERSION array(1,4,9);
  27.  
  28. /**
  29.  * There can be a circular issue with includes, where the $version string is
  30.  * referenced by the include of global.php, etc. before it's defined.
  31.  * For that reason, bring in global.php AFTER we define the version strings.
  32.  */
  33. require_once(SM_PATH 'functions/global.php');
  34.  
  35. /**
  36.  * Wraps text at $wrap characters
  37.  *
  38.  * Has a problem with special HTML characters, so call this before
  39.  * you do character translation.
  40.  *
  41.  * Specifically, &#039 comes up as 5 characters instead of 1.
  42.  * This should not add newlines to the end of lines.
  43.  */
  44. function sqWordWrap(&$line$wrap$charset=null{
  45.     global $languages$squirrelmail_language;
  46.  
  47.     if (isset($languages[$squirrelmail_language]['XTRA_CODE']&&
  48.         function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) {
  49.         if (mb_detect_encoding($line!= 'ASCII'{
  50.             $line $languages[$squirrelmail_language]['XTRA_CODE']('wordwrap'$line$wrap);
  51.             return;
  52.         }
  53.     }
  54.  
  55.     ereg("^([\t >]*)([^\t >].*)?$"$line$regs);
  56.     $beginning_spaces $regs[1];
  57.     if (isset($regs[2])) {
  58.         $words explode(' '$regs[2]);
  59.     else {
  60.         $words '';
  61.     }
  62.  
  63.     $i 0;
  64.     $line $beginning_spaces;
  65.  
  66.     while ($i count($words)) {
  67.         /* Force one word to be on a line (minimum) */
  68.         $line .= $words[$i];
  69.         $line_len strlen($beginning_spacessq_strlen($words[$i],$charset2;
  70.         if (isset($words[$i 1]))
  71.             $line_len += sq_strlen($words[$i 1],$charset);
  72.         $i ++;
  73.  
  74.         /* Add more words (as long as they fit) */
  75.         while ($line_len $wrap && $i count($words)) {
  76.             $line .= ' ' $words[$i];
  77.             $i++;
  78.             if (isset($words[$i]))
  79.                 $line_len += sq_strlen($words[$i],$charset1;
  80.             else
  81.                 $line_len += 1;
  82.         }
  83.  
  84.         /* Skip spaces if they are the first thing on a continued line */
  85.         while (!isset($words[$i]&& $i count($words)) {
  86.             $i ++;
  87.         }
  88.  
  89.         /* Go to the next line if we have more to process */
  90.         if ($i count($words)) {
  91.             $line .= "\n";
  92.         }
  93.     }
  94. }
  95.  
  96. /**
  97.  * Does the opposite of sqWordWrap()
  98.  * @param string body the text to un-wordwrap
  99.  * @return void 
  100.  */
  101. function sqUnWordWrap(&$body{
  102.     global $squirrelmail_language;
  103.  
  104.     if ($squirrelmail_language == 'ja_JP'{
  105.         return;
  106.     }
  107.  
  108.     $lines explode("\n"$body);
  109.     $body '';
  110.     $PreviousSpaces '';
  111.     $cnt count($lines);
  112.     for ($i 0$i $cnt$i ++{
  113.         preg_match("/^([\t >]*)([^\t >].*)?$/"$lines[$i]$regs);
  114.         $CurrentSpaces $regs[1];
  115.         if (isset($regs[2])) {
  116.             $CurrentRest $regs[2];
  117.         else {
  118.             $CurrentRest '';
  119.         }
  120.  
  121.         if ($i == 0{
  122.             $PreviousSpaces $CurrentSpaces;
  123.             $body $lines[$i];
  124.         else if (($PreviousSpaces == $CurrentSpaces/* Do the beginnings match */
  125.                    && (strlen($lines[$i 1]65)    /* Over 65 characters long */
  126.                    && strlen($CurrentRest)) {          /* and there's a line to continue with */
  127.             $body .= ' ' $CurrentRest;
  128.         else {
  129.             $body .= "\n" $lines[$i];
  130.             $PreviousSpaces $CurrentSpaces;
  131.         }
  132.     }
  133.     $body .= "\n";
  134. }
  135.  
  136. /**
  137.  * Truncates a string and take care of html encoded characters
  138.  *
  139.  * @param string  $s string to truncate
  140.  * @param int $iTrimAt Trim at nn characters
  141.  * @return string  Trimmed string
  142.  */
  143. function truncateWithEntities($s$iTrimAt{
  144.     global $languages$squirrelmail_language;
  145.  
  146.     $ent_strlen strlen($s);
  147.     if (($iTrimAt <= 0|| ($ent_strlen <= $iTrimAt))
  148.         return $s;
  149.  
  150.  
  151.     if (isset($languages[$squirrelmail_language]['XTRA_CODE']&&
  152.         function_exists($languages[$squirrelmail_language]['XTRA_CODE'])) {
  153.             return $languages[$squirrelmail_language]['XTRA_CODE']('strimwidth'$s$iTrimAt);
  154.     else {
  155.         /*
  156.          * see if this is entities-encoded string
  157.          * If so, Iterate through the whole string, find out
  158.          * the real number of characters, and if more
  159.          * than $iTrimAt, substr with an updated trim value.
  160.          */
  161.         $trim_val $iTrimAt;
  162.         $ent_offset 0;
  163.         $ent_loc 0;
  164.         while $ent_loc $trim_val && (($ent_loc strpos($s'&'$ent_offset)) !== false&&
  165.                 (($ent_loc_end strpos($s';'$ent_loc+3)) !== false) ) {
  166.             $trim_val += ($ent_loc_end-$ent_loc);
  167.             $ent_offset  $ent_loc_end+1;
  168.         }
  169.  
  170.         if (($trim_val $iTrimAt&& ($ent_strlen $trim_val&& (strpos($s,';',$trim_val($trim_val 6))) {
  171.             $i strpos($s,';',$trim_val);
  172.             if ($i !== false{
  173.                 $trim_val strpos($s,';',$trim_val)+1;
  174.             }
  175.         }
  176.         // only print '...' when we're actually dropping part of the subject
  177.         if ($ent_strlen <= $trim_val)
  178.             return $s;
  179.     }
  180.  
  181.     return substr_replace($s'...'$trim_val);
  182. }
  183.  
  184. /**
  185.  * If $haystack is a full mailbox name and $needle is the mailbox
  186.  * separator character, returns the last part of the mailbox name.
  187.  *
  188.  * @param string haystack full mailbox name to search
  189.  * @param string needle the mailbox separator character
  190.  * @return string the last part of the mailbox name
  191.  */
  192. function readShortMailboxName($haystack$needle{
  193.  
  194.     if ($needle == ''{
  195.         $elem $haystack;
  196.     else {
  197.         $parts explode($needle$haystack);
  198.         $elem array_pop($parts);
  199.         while ($elem == '' && count($parts)) {
  200.             $elem array_pop($parts);
  201.         }
  202.     }
  203.     return$elem );
  204. }
  205.  
  206. /**
  207.  * php_self
  208.  *
  209.  * Creates an URL for the page calling this function, using either the PHP global
  210.  * REQUEST_URI, or the PHP global PHP_SELF with QUERY_STRING added.
  211.  *
  212.  * @return string the complete url for this page
  213.  */
  214. function php_self ({
  215.     if sqgetGlobalVar('REQUEST_URI'$req_uriSQ_SERVER&& !empty($req_uri) ) {
  216.       return $req_uri;
  217.     }
  218.  
  219.     if sqgetGlobalVar('PHP_SELF'$php_selfSQ_SERVER&& !empty($php_self) ) {
  220.  
  221.       // need to add query string to end of PHP_SELF to match REQUEST_URI
  222.       //
  223.       if sqgetGlobalVar('QUERY_STRING'$query_stringSQ_SERVER&& !empty($query_string) ) {
  224.          $php_self .= '?' $query_string;
  225.       }
  226.  
  227.       return $php_self;
  228.     }
  229.  
  230.     return '';
  231. }
  232.  
  233.  
  234. /**
  235.  * Find out where squirrelmail lives and try to be smart about it.
  236.  * The only problem would be when squirrelmail lives in directories
  237.  * called "src", "functions", or "plugins", but people who do that need
  238.  * to be beaten with a steel pipe anyway.
  239.  *
  240.  * @return string the base uri of squirrelmail installation.
  241.  */
  242. function sqm_baseuri(){
  243.     global $base_uri$PHP_SELF;
  244.     /**
  245.      * If it is in the session, just return it.
  246.      */
  247.     if (sqgetGlobalVar('base_uri',$base_uri,SQ_SESSION)){
  248.         return $base_uri;
  249.     }
  250.     $dirs array('|src/.*|''|plugins/.*|''|functions/.*|');
  251.     $repl array('''''');
  252.     $base_uri preg_replace($dirs$repl$PHP_SELF);
  253.     return $base_uri;
  254. }
  255.  
  256. /**
  257.  * get_location
  258.  *
  259.  * Determines the location to forward to, relative to your server.
  260.  * This is used in HTTP Location: redirects.
  261.  * If set, it uses $config_location_base as the first part of the URL,
  262.  * specifically, the protocol, hostname and port parts. The path is
  263.  * always autodetected.
  264.  *
  265.  * @return string the base url for this SquirrelMail installation
  266.  */
  267. function get_location ({
  268.  
  269.  
  270.     /* Get the path, handle virtual directories */
  271.     if(strpos(php_self()'?')) {
  272.         $path substr(php_self()0strpos(php_self()'?'));
  273.     else {
  274.         $path php_self();
  275.     }
  276.     $path substr($path0strrpos($path'/'));
  277.  
  278.     // proto+host+port are already set in config:
  279.     if !empty($config_location_base) ) {
  280.         // register it in the session just in case some plugin depends on this
  281.         sqsession_register($config_location_base $path'sq_base_url');
  282.         return $config_location_base $path ;
  283.     }
  284.     // we computed it before, get it from the session:
  285.     if sqgetGlobalVar('sq_base_url'$full_urlSQ_SESSION) ) {
  286.         return $full_url $path;
  287.     }
  288.     // else: autodetect
  289.  
  290.     /* Check if this is a HTTPS or regular HTTP request. */
  291.     $proto 'http://';
  292.  
  293.     /*
  294.      * If you have 'SSLOptions +StdEnvVars' in your apache config
  295.      *     OR if you have HTTPS=on in your HTTP_SERVER_VARS
  296.      *     OR if you are on port 443
  297.      */
  298.     $getEnvVar getenv('HTTPS');
  299.     if ((isset($getEnvVar&& strcasecmp($getEnvVar'on'=== 0||
  300.         (sqgetGlobalVar('HTTPS'$https_onSQ_SERVER&& strcasecmp($https_on'on'=== 0||
  301.         (sqgetGlobalVar('SERVER_PORT'$server_portSQ_SERVER&&  $server_port == 443)) {
  302.         $proto 'https://';
  303.     }
  304.  
  305.     /* Get the hostname from the Host header or server config. */
  306.     if !sqgetGlobalVar('HTTP_X_FORWARDED_HOST'$hostSQ_SERVER|| empty($host) ) {
  307.         if !sqgetGlobalVar('HTTP_HOST'$hostSQ_SERVER|| empty($host) ) {
  308.             if !sqgetGlobalVar('SERVER_NAME'$hostSQ_SERVER|| empty($host) ) {
  309.                 $host '';
  310.             }
  311.         }
  312.     }
  313.  
  314.     $port '';
  315.     if (strstr($host':')) {
  316.         if (sqgetGlobalVar('SERVER_PORT'$server_portSQ_SERVER)) {
  317.             if (($server_port != 80 && $proto == 'http://'||
  318.                 ($server_port != 443 && $proto == 'https://')) {
  319.                 $port sprintf(':%d'$server_port);
  320.             }
  321.         }
  322.     }
  323.  
  324.    /* this is a workaround for the weird macosx caching that
  325.       causes Apache to return 16080 as the port number, which causes
  326.       SM to bail */
  327.  
  328.    if ($imap_server_type == 'macosx' && $port == ':16080'{
  329.         $port '';
  330.    }
  331.  
  332.    /* Fallback is to omit the server name and use a relative */
  333.    /* URI, although this is not RFC 2616 compliant.          */
  334.    $full_url ($host $proto $host $port '');
  335.    sqsession_register($full_url'sq_base_url');
  336.    return $full_url $path;
  337. }
  338.  
  339.  
  340. /**
  341.  * Encrypts password
  342.  *
  343.  * These functions are used to encrypt the password before it is
  344.  * stored in a cookie. The encryption key is generated by
  345.  * OneTimePadCreate();
  346.  *
  347.  * @param string string the (password)string to encrypt
  348.  * @param string epad the encryption key
  349.  * @return string the base64-encoded encrypted password
  350.  */
  351. function OneTimePadEncrypt ($string$epad{
  352.     $pad base64_decode($epad);
  353.  
  354.     if (strlen($pad)>0{
  355.         // make sure that pad is longer than string
  356.         while (strlen($string)>strlen($pad)) {
  357.             $pad.=$pad;
  358.         }
  359.     else {
  360.         // FIXME: what should we do when $epad is not base64 encoded or empty.
  361.     }
  362.  
  363.     $encrypted '';
  364.     for ($i 0$i strlen ($string)$i++{
  365.         $encrypted .= chr (ord($string[$i]ord($pad[$i]));
  366.     }
  367.  
  368.     return base64_encode($encrypted);
  369. }
  370.  
  371. /**
  372.  * Decrypts a password from the cookie
  373.  *
  374.  * Decrypts a password from the cookie, encrypted by OneTimePadEncrypt.
  375.  * This uses the encryption key that is stored in the session.
  376.  *
  377.  * @param string string the string to decrypt
  378.  * @param string epad the encryption key from the session
  379.  * @return string the decrypted password
  380.  */
  381. function OneTimePadDecrypt ($string$epad{
  382.     $pad base64_decode($epad);
  383.  
  384.     if (strlen($pad)>0{
  385.         // make sure that pad is longer than string
  386.         while (strlen($string)>strlen($pad)) {
  387.             $pad.=$pad;
  388.         }
  389.     else {
  390.         // FIXME: what should we do when $epad is not base64 encoded or empty.
  391.     }
  392.  
  393.     $encrypted base64_decode ($string);
  394.     $decrypted '';
  395.     for ($i 0$i strlen ($encrypted)$i++{
  396.         $decrypted .= chr (ord($encrypted[$i]ord($pad[$i]));
  397.     }
  398.  
  399.     return $decrypted;
  400. }
  401.  
  402.  
  403. /**
  404.  * Randomizes the mt_rand() function.
  405.  *
  406.  * Toss this in strings or integers and it will seed the generator
  407.  * appropriately. With strings, it is better to get them long.
  408.  * Use md5() to lengthen smaller strings.
  409.  *
  410.  * @param mixed val a value to seed the random number generator
  411.  * @return void 
  412.  */
  413. function sq_mt_seed($Val{
  414.     /* if mt_getrandmax() does not return a 2^n - 1 number,
  415.        this might not work well.  This uses $Max as a bitmask. */
  416.     $Max mt_getrandmax();
  417.  
  418.     if (is_int($Val)) {
  419.             $Val crc32($Val);
  420.     }
  421.  
  422.     if ($Val 0{
  423.         $Val *= -1;
  424.     }
  425.  
  426.     if ($Val == 0{
  427.         return;
  428.     }
  429.  
  430.     mt_srand(($Val mt_rand(0$Max)) $Max);
  431. }
  432.  
  433.  
  434. /**
  435.  * Init random number generator
  436.  *
  437.  * This function initializes the random number generator fairly well.
  438.  * It also only initializes it once, so you don't accidentally get
  439.  * the same 'random' numbers twice in one session.
  440.  *
  441.  * @return void 
  442.  */
  443. function sq_mt_randomize({
  444.     static $randomized;
  445.  
  446.     if ($randomized{
  447.         return;
  448.     }
  449.  
  450.     /* Global. */
  451.     sqgetGlobalVar('REMOTE_PORT'$remote_portSQ_SERVER);
  452.     sqgetGlobalVar('REMOTE_ADDR'$remote_addrSQ_SERVER);
  453.     sq_mt_seed((int)((double) microtime(1000000));
  454.     sq_mt_seed(md5($remote_port $remote_addr getmypid()));
  455.  
  456.     /* getrusage */
  457.     if (function_exists('getrusage')) {
  458.         /* Avoid warnings with Win32 */
  459.         $dat @getrusage();
  460.         if (isset($dat&& is_array($dat)) {
  461.             $Str '';
  462.             foreach ($dat as $k => $v)
  463.                 {
  464.                     $Str .= $k $v;
  465.                 }
  466.             sq_mt_seed(md5($Str));
  467.         }
  468.     }
  469.  
  470.     if(sqgetGlobalVar('UNIQUE_ID'$unique_idSQ_SERVER)) {
  471.         sq_mt_seed(md5($unique_id));
  472.     }
  473.  
  474.     $randomized 1;
  475. }
  476.  
  477. /**
  478.  * Creates encryption key
  479.  *
  480.  * Creates an encryption key for encrypting the password stored in the cookie.
  481.  * The encryption key itself is stored in the session.
  482.  *
  483.  * @param int length optional, length of the string to generate
  484.  * @return string the encryption key
  485.  */
  486. function OneTimePadCreate ($length=100{
  487.     sq_mt_randomize();
  488.  
  489.     $pad '';
  490.     for ($i 0$i $length$i++{
  491.         $pad .= chr(mt_rand(0,255));
  492.     }
  493.  
  494.     return base64_encode($pad);
  495. }
  496.  
  497. /**
  498.  * Returns a string showing the size of the message/attachment.
  499.  *
  500.  * @param int bytes the filesize in bytes
  501.  * @return string the filesize in human readable format
  502.  */
  503. function show_readable_size($bytes{
  504.     $bytes /= 1024;
  505.     $type 'k';
  506.  
  507.     if ($bytes 1024 1{
  508.         $bytes /= 1024;
  509.         $type 'M';
  510.     }
  511.  
  512.     if ($bytes 10{
  513.         $bytes *= 10;
  514.         settype($bytes'integer');
  515.         $bytes /= 10;
  516.     else {
  517.         settype($bytes'integer');
  518.     }
  519.  
  520.     return $bytes '<small>&nbsp;' $type '</small>';
  521. }
  522.  
  523. /**
  524.  * Generates a random string from the caracter set you pass in
  525.  *
  526.  * @param int size the size of the string to generate
  527.  * @param string chars a string containing the characters to use
  528.  * @param int flags a flag to add a specific set to the characters to use:
  529.  *      Flags:
  530.  *        1 = add lowercase a-z to $chars
  531.  *        2 = add uppercase A-Z to $chars
  532.  *        4 = add numbers 0-9 to $chars
  533.  * @return string the random string
  534.  */
  535. function GenerateRandomString($size$chars$flags 0{
  536.     if ($flags 0x1{
  537.         $chars .= 'abcdefghijklmnopqrstuvwxyz';
  538.     }
  539.     if ($flags 0x2{
  540.         $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  541.     }
  542.     if ($flags 0x4{
  543.         $chars .= '0123456789';
  544.     }
  545.  
  546.     if (($size 1|| (strlen($chars1)) {
  547.         return '';
  548.     }
  549.  
  550.     sq_mt_randomize()/* Initialize the random number generator */
  551.  
  552.     $String '';
  553.     $j strlen$chars 1;
  554.     while (strlen($String$size{
  555.         $String .= $chars{mt_rand(0$j)};
  556.     }
  557.  
  558.     return $String;
  559. }
  560.  
  561. /**
  562.  * Escapes special characters for use in IMAP commands.
  563.  *
  564.  * @param string the string to escape
  565.  * @return string the escaped string
  566.  */
  567. function quoteimap($str{
  568.     return preg_replace("/([\"\\\\])/""\\\\$1"$str);
  569. }
  570.  
  571. /**
  572.  * Trims array
  573.  *
  574.  * Trims every element in the array, ie. remove the first char of each element
  575.  * Obsolete: will probably removed soon
  576.  * @param array array the array to trim
  577.  * @obsolete
  578.  */
  579. function TrimArray(&$array{
  580.     foreach ($array as $k => $v{
  581.         global $$k;
  582.         if (is_array($$k)) {
  583.             foreach ($$k as $k2 => $v2{
  584.                 $$k[$k2substr($v21);
  585.             }
  586.         else {
  587.             $$k substr($v1);
  588.         }
  589.  
  590.         /* Re-assign back to array. */
  591.         $array[$k= $$k;
  592.     }
  593. }
  594.  
  595. /**
  596.  * Removes slashes from every element in the array
  597.  */
  598. function RemoveSlashes(&$array{
  599.     foreach ($array as $k => $v{
  600.         global $$k;
  601.         if (is_array($$k)) {
  602.             foreach ($$k as $k2 => $v2{
  603.                 $newArray[stripslashes($k2)stripslashes($v2);
  604.             }
  605.             $$k $newArray;
  606.         else {
  607.             $$k stripslashes($v);
  608.         }
  609.  
  610.         /* Re-assign back to the array. */
  611.         $array[$k= $$k;
  612.     }
  613. }
  614.  
  615. /**
  616.  * Create compose link
  617.  *
  618.  * Returns a link to the compose-page, taking in consideration
  619.  * the compose_in_new and javascript settings.
  620.  * @param string url the URL to the compose page
  621.  * @param string text the link text, default "Compose"
  622.  * @return string a link to the compose page
  623.  */
  624. function makeComposeLink($url$text null$target='')
  625. {
  626.     global $compose_new_win,$javascript_on;
  627.  
  628.     if(!$text{
  629.         $text _("Compose");
  630.     }
  631.  
  632.  
  633.     // if not using "compose in new window", make
  634.     // regular link and be done with it
  635.     if($compose_new_win != '1'{
  636.         return makeInternalLink($url$text$target);
  637.     }
  638.  
  639.  
  640.     // build the compose in new window link...
  641.  
  642.  
  643.     // if javascript is on, use onClick event to handle it
  644.     if($javascript_on{
  645.         sqgetGlobalVar('base_uri'$base_uriSQ_SESSION);
  646.         return '<a href="javascript:void(0)" onclick="comp_in_new(\''.$base_uri.$url.'\')">'$text.'</a>';
  647.     }
  648.  
  649.  
  650.     // otherwise, just open new window using regular HTML
  651.     return makeInternalLink($url$text'_blank');
  652.  
  653. }
  654.  
  655. /**
  656.  * Print variable
  657.  *
  658.  * sm_print_r($some_variable, [$some_other_variable [, ...]]);
  659.  *
  660.  * Debugging function - does the same as print_r, but makes sure special
  661.  * characters are converted to htmlentities first.  This will allow
  662.  * values like <[email protected]> to be displayed.
  663.  * The output is wrapped in <<pre>> and <</pre>> tags.
  664.  *
  665.  * @return void 
  666.  */
  667. function sm_print_r({
  668.     ob_start();  // Buffer output
  669.     foreach(func_get_args(as $var{
  670.         print_r($var);
  671.         echo "\n";
  672.     }
  673.     $buffer ob_get_contents()// Grab the print_r output
  674.     ob_end_clean();  // Silently discard the output & stop buffering
  675.     print '<pre>';
  676.     print htmlentities($buffer);
  677.     print '</pre>';
  678. }
  679.  
  680. /**
  681.  * version of fwrite which checks for failure
  682.  */
  683. function sq_fwrite($fp$string{
  684.         // write to file
  685.         $count @fwrite($fp,$string);
  686.         // the number of bytes written should be the length of the string
  687.         if($count != strlen($string)) {
  688.                 return FALSE;
  689.         }
  690.  
  691.         return $count;
  692. }
  693. /**
  694.  * Tests if string contains 8bit symbols.
  695.  *
  696.  * If charset is not set, function defaults to default_charset.
  697.  * $default_charset global must be set correctly if $charset is
  698.  * not used.
  699.  * @param string $string tested string
  700.  * @param string $charset charset used in a string
  701.  * @return bool true if 8bit symbols are detected
  702.  * @since 1.5.1 and 1.4.4
  703.  */
  704. function sq_is8bit($string,$charset=''{
  705.     global $default_charset;
  706.  
  707.     if ($charset==''$charset=$default_charset;
  708.  
  709.     /**
  710.      * Don't use \240 in ranges. Sometimes RH 7.2 doesn't like it.
  711.      * Don't use \200-\237 for iso-8859-x charsets. This ranges
  712.      * stores control symbols in those charsets.
  713.      * Use preg_match instead of ereg in order to avoid problems
  714.      * with mbstring overloading
  715.      */
  716.     if (preg_match("/^iso-8859/i",$charset)) {
  717.         $needle='/\240|[\241-\377]/';
  718.     else {
  719.         $needle='/[\200-\237]|\240|[\241-\377]/';
  720.     }
  721.     return preg_match("$needle",$string);
  722. }
  723.  
  724. /**
  725.  * Function returns number of characters in string.
  726.  *
  727.  * Returned number might be different from number of bytes in string,
  728.  * if $charset is multibyte charset. Detection depends on mbstring
  729.  * functions. If mbstring does not support tested multibyte charset,
  730.  * vanilla string length function is used.
  731.  * @param string $str string
  732.  * @param string $charset charset
  733.  * @since 1.5.1 and 1.4.6
  734.  * @return integer number of characters in string
  735.  */
  736. function sq_strlen($str$charset=null){
  737.     // default option
  738.     if (is_null($charset)) return strlen($str);
  739.  
  740.     // lowercase charset name
  741.     $charset=strtolower($charset);
  742.  
  743.     // use automatic charset detection, if function call asks for it
  744.     if ($charset=='auto'{
  745.         global $default_charset;
  746.         set_my_charset();
  747.         $charset=$default_charset;
  748.     }
  749.  
  750.     // Use mbstring only with listed charsets
  751.     $aList_of_mb_charsets=array('utf-8','big5','gb2312','gb18030','euc-jp','euc-cn','euc-tw','euc-kr');
  752.  
  753.     // calculate string length according to charset
  754.     if (in_array($charset,$aList_of_mb_charsets&& in_array($charset,sq_mb_list_encodings())) {
  755.         $real_length mb_strlen($str,$charset);
  756.     else {
  757.         // own strlen detection code is removed because missing strpos,
  758.         // strtoupper and substr implementations break string wrapping.
  759.         $real_length=strlen($str);
  760.     }
  761.     return $real_length;
  762. }
  763.  
  764. /**
  765.  * Replacement of mb_list_encodings function
  766.  *
  767.  * This function provides replacement for function that is available only
  768.  * in php 5.x. Function does not test all mbstring encodings. Only the ones
  769.  * that might be used in SM translations.
  770.  *
  771.  * Supported strings are stored in session in order to reduce number of
  772.  * mb_internal_encoding function calls.
  773.  *
  774.  * If mb_list_encodings() function is present, code uses it. Main difference
  775.  * from original function behaviour - array values are lowercased in order to
  776.  * simplify use of returned array in in_array() checks.
  777.  *
  778.  * If you want to test all mbstring encodings - fill $list_of_encodings
  779.  * array.
  780.  * @return array list of encodings supported by php mbstring extension
  781.  * @since 1.5.1 and 1.4.6
  782.  */
  783. function sq_mb_list_encodings({
  784.     // check if mbstring extension is present
  785.     if (function_exists('mb_internal_encoding'))
  786.         return array();
  787.  
  788.     // php 5+ function
  789.     if (function_exists('mb_list_encodings')) {
  790.         $ret mb_list_encodings();
  791.         array_walk($ret,'sq_lowercase_array_vals');
  792.         return $ret;
  793.     }
  794.  
  795.     // don't try to test encodings, if they are already stored in session
  796.     if (sqgetGlobalVar('mb_supported_encodings',$mb_supported_encodings,SQ_SESSION))
  797.         return $mb_supported_encodings;
  798.  
  799.     // save original encoding
  800.     $orig_encoding=mb_internal_encoding();
  801.  
  802.     $list_of_encoding=array(
  803.         'pass',
  804.         'auto',
  805.         'ascii',
  806.         'jis',
  807.         'utf-8',
  808.         'sjis',
  809.         'euc-jp',
  810.         'iso-8859-1',
  811.         'iso-8859-2',
  812.         'iso-8859-7',
  813.         'iso-8859-9',
  814.         'iso-8859-15',
  815.         'koi8-r',
  816.         'koi8-u',
  817.         'big5',
  818.         'gb2312',
  819.         'gb18030',
  820.         'windows-1251',
  821.         'windows-1255',
  822.         'windows-1256',
  823.         'tis-620',
  824.         'iso-2022-jp',
  825.         'euc-cn',
  826.         'euc-kr',
  827.         'euc-tw',
  828.         'uhc',
  829.         'utf7-imap');
  830.  
  831.     $supported_encodings=array();
  832.  
  833.     foreach ($list_of_encoding as $encoding{
  834.         // try setting encodings. suppress warning messages
  835.         if (@mb_internal_encoding($encoding))
  836.             $supported_encodings[]=$encoding;
  837.     }
  838.  
  839.     // restore original encoding
  840.     mb_internal_encoding($orig_encoding);
  841.  
  842.     // register list in session
  843.     sqsession_register($supported_encodings,'mb_supported_encodings');
  844.  
  845.     return $supported_encodings;
  846. }
  847.  
  848. /**
  849.  * Callback function used to lowercase array values.
  850.  * @param string $val array value
  851.  * @param mixed $key array key
  852.  * @since 1.5.1 and 1.4.6
  853.  */
  854. function sq_lowercase_array_vals(&$val,$key{
  855.     $val strtolower($val);
  856. }
  857.  
  858. /**
  859.  * Callback function to trim whitespace from a value, to be used in array_walk
  860.  * @param string $value value to trim
  861.  * @since 1.5.2 and 1.4.7
  862.  */
  863. function sq_trim_value &$value {
  864.     $value trim($value);
  865. }
  866.  
  867.  
  868. $PHP_SELF php_self();
  869. ?>

Documentation generated on Sat, 07 Oct 2006 16:33:53 +0300 by phpDocumentor 1.3.0RC6