From 1323ebf98b009e8c1d9fa6477ef1be938bf6e2e3 Mon Sep 17 00:00:00 2001
From: robocoder <anthon.pang@gmail.com>
Date: Sun, 13 Nov 2011 02:37:04 +0000
Subject: [PATCH] fixes #2769 plus refactoring

git-svn-id: http://dev.piwik.org/svn/trunk@5431 59fd770c-687e-43c8-a1e3-f5a4ff64c105
---
 core/Common.php                           | 75 +++++++++++++++++++++++
 core/Http.php                             |  9 ++-
 core/IP.php                               | 32 +++-------
 core/Tracker/Visit.php                    |  3 +-
 core/Visualization/Cloud.php              |  7 +--
 libs/Smarty/plugins/modifier.truncate.php | 21 +++++--
 plugins/AnonymizeIP/AnonymizeIP.php       |  4 +-
 plugins/Proxy/Controller.php              |  3 +-
 8 files changed, 109 insertions(+), 45 deletions(-)

diff --git a/core/Common.php b/core/Common.php
index 7b49f0b9fb..a75e151269 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -553,6 +553,81 @@ class Piwik_Common
 		return (0 !== preg_match('/(^[a-zA-Z0-9]+([a-zA-Z_0-9.-]*))$/D', $filename));
 	}
 
+/*
+ * String operations
+ */
+
+	/**
+	 * byte-oriented substr() - ASCII
+	 *
+	 * @param string $string
+	 * @param int $start
+	 * @param int $length optional length
+	 * @return string
+	 */
+	static public function substr($string, $start)
+	{
+		// in case mbstring overloads substr function
+		$substr = function_exists('mb_orig_substr') ? 'mb_orig_substr' : 'substr';
+
+		$length = func_num_args() > 2
+			? func_get_arg(2)
+			: self::strlen($string);
+
+		return $substr($string, $start, $length);
+	}
+
+	/**
+	 * byte-oriented strlen() - ASCII
+	 *
+	 * @param string $string
+	 * @return int
+	 */
+	static public function strlen($string)
+	{
+		// in case mbstring overloads strlen function
+		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
+		return $strlen($string);
+	}
+
+	/**
+	 * multi-byte substr() - UTF-8
+	 *
+	 * @param string $string
+	 * @param int $start
+	 * @param int $length optional length
+	 * @return string
+	 */
+	static public function mb_substr($string, $start)
+	{
+		$length = func_num_args() > 2
+			? func_get_arg(2)
+			: self::mb_strlen($string);
+
+		if (function_exists('mb_substr'))
+		{
+			return mb_substr($string, $start, $length, 'UTF-8');
+		}
+
+		return substr($string, $start, $length);
+	}
+
+	/**
+	 * multi-byte strlen() - UTF-8
+	 *
+	 * @param string $string
+	 * @return int
+	 */
+	static public function mb_strlen($string)
+	{
+		if (function_exists('mb_strlen'))
+		{
+			return mb_strlen($string, 'UTF-8');
+		}
+
+		return strlen($string);
+	}
+
 /*
  * Escaping input
  */
diff --git a/core/Http.php b/core/Http.php
index 90db47b3f9..6cfaf372af 100644
--- a/core/Http.php
+++ b/core/Http.php
@@ -92,7 +92,6 @@ class Piwik_Http
 			throw new Exception('Too many redirects ('.$followDepth.')');
 		}
 
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
 		$contentLength = 0;
 		$fileLength = 0;
 
@@ -285,7 +284,7 @@ class Piwik_Http
 					throw new Exception('Timed out waiting for server response');
 				}
 
-				$fileLength += $strlen($line);
+				$fileLength += Piwik_Common::strlen($line);
 
 				if(is_resource($file))
 				{
@@ -345,7 +344,7 @@ class Piwik_Http
 				while(!feof($handle))
 				{
 					$response = fread($handle, 8192);
-					$fileLength += $strlen($response);
+					$fileLength += Piwik_Common::strlen($response);
 					fwrite($file, $response);
 				}
 				fclose($handle);
@@ -353,7 +352,7 @@ class Piwik_Http
 			else
 			{
 				$response = @file_get_contents($aUrl, 0, $ctx);
-				$fileLength = $strlen($response);
+				$fileLength = Piwik_Common::strlen($response);
 			}
 
 			// restore the socket_timeout value
@@ -445,7 +444,7 @@ class Piwik_Http
 			}
 
 			$contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
-			$fileLength = is_resource($file) ? curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD) : $strlen($response);
+			$fileLength = is_resource($file) ? curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD) : Piwik_Common::strlen($response);
 
 			@curl_close($ch);
 			unset($ch);
diff --git a/core/IP.php b/core/IP.php
index 4629c8c8a3..08dae1ff23 100644
--- a/core/IP.php
+++ b/core/IP.php
@@ -111,9 +111,6 @@ class Piwik_IP
 	 */
 	static public function sanitizeIpRange($ipRangeString)
 	{
-		// in case mbstring overloads strlen function
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-
 		$ipRangeString = trim($ipRangeString);
 		if(empty($ipRangeString))
 		{
@@ -143,7 +140,7 @@ class Piwik_IP
 		if(($ip = @_inet_pton($ipRangeString)) === false)
 			return false;
 
-		$maxbits = $strlen($ip) * 8;
+		$maxbits = Piwik_Common::strlen($ip) * 8;
 		if(!isset($bits))
 			$bits = $maxbits;
 
@@ -207,24 +204,20 @@ class Piwik_IP
 	 */
 	static public function long2ip($ip)
 	{
-		// in case mbstring overloads strlen and substr functions
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-		$substr = function_exists('mb_orig_substr') ? 'mb_orig_substr' : 'substr';
-
 		// IPv4
-		if($strlen($ip) == 4)
+		if(Piwik_Common::strlen($ip) == 4)
 		{
 			return self::N2P($ip);
 		}
 
 		// IPv6 - transitional address?
-		if($strlen($ip) == 16)
+		if(Piwik_Common::strlen($ip) == 16)
 		{
 			if(substr_compare($ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 0, 12) === 0
 				|| substr_compare($ip, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 0, 12) === 0)
 			{
 				// remap 128-bit IPv4-mapped and IPv4-compat addresses
-				return self::N2P($substr($ip, 12));
+				return self::N2P(Piwik_Common::substr($ip, 12));
 			}
 		}
 
@@ -239,9 +232,6 @@ class Piwik_IP
 	 */
 	static public function getIpsForRange($ipRange)
 	{
-		// in case mbstring overloads strlen function
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-
 		if(strpos($ipRange, '/') === false)
 		{
 			$ipRange = self::sanitizeIpRange($ipRange);
@@ -256,7 +246,7 @@ class Piwik_IP
 			return false;
 		}
 
-		$lowLen = $strlen($low);
+		$lowLen = Piwik_Common::strlen($low);
 		$i = $lowLen - 1;
 		$bits = $lowLen * 8 - $bits;
 
@@ -287,10 +277,7 @@ class Piwik_IP
 	 */
 	static public function isIpInRange($ip, $ipRanges)
 	{
-		// in case mbstring overloads strlen function
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-
-		$ipLen = $strlen($ip);
+		$ipLen = Piwik_Common::strlen($ip);
 		if(empty($ip) || empty($ipRanges) || ($ipLen != 4 && $ipLen != 16))
 		{
 			return false;
@@ -316,7 +303,7 @@ class Piwik_IP
 
 			$low = $range[0];
 			$high = $range[1];
-			if($strlen($low) != $ipLen)
+			if(Piwik_Common::strlen($low) != $ipLen)
 			{
 				continue;
 			}
@@ -461,12 +448,9 @@ class Piwik_IP
  */
 function php_compat_inet_ntop($in_addr)
 {
-	// in case mbstring overloads strlen function
-	$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-
 	$r = bin2hex($in_addr);
 
-	switch ($strlen($in_addr))
+	switch (Piwik_Common::strlen($in_addr))
 	{
 		case 4:
 			// IPv4 address
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index debd77d707..0053672271 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -1251,8 +1251,7 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
 	protected function getConfigHash( $os, $browserName, $browserVersion, $resolution, $plugin_Flash, $plugin_Java, $plugin_Director, $plugin_Quicktime, $plugin_RealPlayer, $plugin_PDF, $plugin_WindowsMedia, $plugin_Gears, $plugin_Silverlight, $plugin_Cookie, $ip, $browserLang)
 	{
 		$hash = md5( $os . $browserName . $browserVersion . $plugin_Flash . $plugin_Java . $plugin_Director . $plugin_Quicktime . $plugin_RealPlayer . $plugin_PDF . $plugin_WindowsMedia . $plugin_Gears . $plugin_Silverlight . $plugin_Cookie . $ip . $browserLang, $raw_output = true );
-		$substr = function_exists('mb_orig_substr') ? 'mb_orig_substr' : 'substr';
-		return $substr( $hash, 0, Piwik_Tracker::LENGTH_BINARY_ID );
+		return Piwik_Common::substr( $hash, 0, Piwik_Tracker::LENGTH_BINARY_ID );
 	}
 
 	/**
diff --git a/core/Visualization/Cloud.php b/core/Visualization/Cloud.php
index 152c7a9b80..ee1f6c2df7 100644
--- a/core/Visualization/Cloud.php
+++ b/core/Visualization/Cloud.php
@@ -43,9 +43,6 @@ class Piwik_Visualization_Cloud implements Piwik_View_Interface
 
 	public function render()
 	{
-		$strlen = function_exists('mb_strlen') ? 'mb_strlen' : 'strlen';
-		$substr = function_exists('mb_substr') ? 'mb_substr' : 'substr';
-
 		$this->shuffleCloud();
 		$return = array();
 		if(empty($this->wordsArray)) {
@@ -55,9 +52,9 @@ class Piwik_Visualization_Cloud implements Piwik_View_Interface
 		foreach ($this->wordsArray as $word => $popularity)
 		{
 			$wordTruncated = $word;
-			if($strlen($word) > $this->truncatingLimit)
+			if(Piwik_Common::mb_strlen($word) > $this->truncatingLimit)
 			{
-				$wordTruncated = $substr($word, 0, $this->truncatingLimit - 3).'...';
+				$wordTruncated = Piwik_Common::mb_substr($word, 0, $this->truncatingLimit - 3).'...';
 			}
 			
 			// case hideFutureHoursWhenToday=1 shows hours with no visits
diff --git a/libs/Smarty/plugins/modifier.truncate.php b/libs/Smarty/plugins/modifier.truncate.php
index 35c89690a1..ca78977477 100644
--- a/libs/Smarty/plugins/modifier.truncate.php
+++ b/libs/Smarty/plugins/modifier.truncate.php
@@ -30,6 +30,21 @@ function smarty_modifier_truncate($string, $length = 80, $etc = '...',
     if ($length == 0)
         return '';
 
+    if (function_exists('mb_strlen') && function_exists('mb_substr'))
+    {
+        if (mb_strlen($string, 'UTF-8') > $length) {
+            $length -= min($length, mb_strlen($etc, 'UTF-8'));
+            if (!$break_words && !$middle) {
+                $string = preg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length+1, 'UTF-8'));
+            }
+            if(!$middle) {
+                return mb_substr($string, 0, $length, 'UTF-8') . $etc;
+            }
+            return mb_substr($string, 0, $length/2, 'UTF-8') . $etc . mb_substr($string, -$length/2, $length/2, 'UTF-8');
+        }
+        return $string;
+    }
+
     if (strlen($string) > $length) {
         $length -= min($length, strlen($etc));
         if (!$break_words && !$middle) {
@@ -37,12 +52,10 @@ function smarty_modifier_truncate($string, $length = 80, $etc = '...',
         }
         if(!$middle) {
             return substr($string, 0, $length) . $etc;
-        } else {
-            return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
         }
-    } else {
-        return $string;
+        return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
     }
+    return $string;
 }
 
 /* vim: set expandtab: */
diff --git a/plugins/AnonymizeIP/AnonymizeIP.php b/plugins/AnonymizeIP/AnonymizeIP.php
index bb6220a10c..cfee9f309d 100644
--- a/plugins/AnonymizeIP/AnonymizeIP.php
+++ b/plugins/AnonymizeIP/AnonymizeIP.php
@@ -50,9 +50,7 @@ class Piwik_AnonymizeIP extends Piwik_Plugin
 	 */
 	static public function applyIPMask($ip, $maskLength)
 	{
-		// in case mbstring overloads strlen function
-		$strlen = function_exists('mb_orig_strlen') ? 'mb_orig_strlen' : 'strlen';
-		$i = $strlen($ip);
+		$i = Piwik_Common::strlen($ip);
 		if($maskLength > $i)
 		{
 			$maskLength = $i;
diff --git a/plugins/Proxy/Controller.php b/plugins/Proxy/Controller.php
index b1af775d80..9f88b17486 100644
--- a/plugins/Proxy/Controller.php
+++ b/plugins/Proxy/Controller.php
@@ -57,9 +57,8 @@ class Piwik_Proxy_Controller extends Piwik_Controller
 		$data = base64_decode($rawData);
 		if($data !== false)
 		{
-			$substr = function_exists('mb_orig_substr') ? 'mb_orig_substr' : 'substr';
 			// check for PNG header
-			if($substr($data, 0, 8) === "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a")
+			if(Piwik_Common::substr($data, 0, 8) === "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a")
 			{
 				header('Content-Type: image/png');
 
-- 
GitLab