Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix for bad encoded strftime() values when LC_TIME has code points higher than 128 #27

Closed
wants to merge 1 commit into from

2 participants

Ber Clausen Mark Story
Ber Clausen

Inside testI18nFormat() test failure is not evident because test case it is not tight enough, If you put a multibyte character inside the test, for example, if you change the line [1] for [2], the actual cake test will fail:

[1] $expected = 'jue 14 ene 2010 13:59:28 ' . strftime('%Z', $time);

[2] $expected = 'mié 13 ene 2010 13:59:28 ' . strftime('%Z', $time);

notice the accented 'é' in the string.

Mark Story
Owner

Why does FormHelper need to change as well? The formatting there doesn't go through the i18n class, so I don't really understand why that changed as well.

Ber Clausen

Yes, I know Mark, but a call to Form::i18nFormat for example, should return a correct value, but strftime fails to do so, that was the main problem when formatting dates trough the form helper.

If Form helper does not change, calls to Multibyte::strftime will work well but calls to Form methods where strftime is used instead of the multibyte version will fail I guess.

Ber Clausen

Sorry Mark, when I wrote Form::i18nFormat I meant Form::dateTime , my bad!

Also Form->__generateOptions() has a call to strftime() which means every other method calling this private function is affected, this being almost every Form method.

Maybe changing those strftime() calls from FormHelper to some other static call inside a TimeHelper multibyte strftime() wrapper function can isolate things a bit... hope this helps (if there is no other way to circumvent this).

Mark Story
Owner

Sure, but how does '%Y-%m-%d %H:%M:%S' get multibyte characters? This is an all numeric dateformat, I don't see why it has to incur the extra overhead of going through Multibyte, when it will never happen.

Ber Clausen

Ohh gosh, you are damn right Mark! I haven't payed attention to both being all numeric strings.
Every change made by this patch inside FromHelper can be thrown away :)

Thanks for the insight!

Ber Clausen

Ohh, if you need me to fix the patch and update it to 1.3.9 for a proper review, please punch me here and I will.

Ber Clausen

In case everything else is good to go:

Fixed and rebased to 1.3 branch from today
bar@fc4de67

Ber Clausen bar closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 11, 2011
  1. Ber Clausen

    Fix for helper functions not returning a valid utf8 string when LC_TIME

    bar authored
    file has characters represented by unicode code point higher than 128.
    Also harden tests.
    (http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/912)
This page is out of date. Refresh to see the latest.
28 cake/libs/multibyte.php
View
@@ -1066,6 +1066,34 @@ function mimeEncode($string, $charset = null, $newline = "\r\n") {
}
/**
+ * Format a local time/date according to locale settings, using the app's encoding
+ *
+ * @return string
+ * @access public
+ * @static
+ */
+ function strftime() {
+ $args = func_get_args();
+ $format = call_user_func_array('strftime', $args);
+ if (function_exists('mb_internal_encoding')) {
+ $encoding = mb_internal_encoding();
+ } else {
+ $encoding = Configure::read('App.encoding');
+ }
+ if (!empty($encoding) && $encoding === 'UTF-8') {
+ if (function_exists('mb_check_encoding')) {
+ $valid = mb_check_encoding($format, $encoding);
+ } else {
+ $valid = !Multibyte::checkMultibyte($format);
+ }
+ if (!$valid) {
+ $format = utf8_encode($format);
+ }
+ }
+ return $format;
+ }
+
+/**
* Return the Code points range for Unicode characters
*
* @param interger $decimal
7 cake/libs/view/helpers/form.php
View
@@ -19,6 +19,9 @@
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+if (!class_exists('Multibyte')) {
+ App::import('Core', 'Multibyte');
+}
/**
* Form helper library.
@@ -1811,7 +1814,7 @@ function dateTime($fieldName, $dateFormat = 'DMY', $timeFormat = '12', $selected
extract($selected);
} else {
if (is_numeric($selected)) {
- $selected = strftime('%Y-%m-%d %H:%M:%S', $selected);
+ $selected = Multibyte::strftime('%Y-%m-%d %H:%M:%S', $selected);
}
$meridian = 'am';
$pos = strpos($selected, '-');
@@ -2135,7 +2138,7 @@ function __generateOptions($name, $options = array()) {
$data = $options['monthNames'];
} else {
for ($m = 1; $m <= 12; $m++) {
- $data[sprintf("%02s", $m)] = strftime("%m", mktime(1, 1, 1, $m, 1, 1999));
+ $data[sprintf("%02s", $m)] = Multibyte::strftime("%m", mktime(1, 1, 1, $m, 1, 1999));
}
}
break;
13 cake/libs/view/helpers/time.php
View
@@ -17,6 +17,9 @@
* @since CakePHP(tm) v 0.10.0.1076
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+if (!class_exists('Multibyte')) {
+ App::import('Core', 'Multibyte');
+}
/**
* Time Helper class for easy use of time data.
@@ -204,7 +207,7 @@ function nice($dateString = null, $userOffset = null) {
$date = time();
}
$format = $this->convertSpecifiers('%a, %b %eS %Y, %H:%M', $date);
- return strftime($format, $date);
+ return Multibyte::strftime($format, $date);
}
/**
@@ -227,12 +230,12 @@ function niceShort($dateString = null, $userOffset = null) {
$y = $this->isThisYear($date) ? '' : ' %Y';
if ($this->isToday($dateString, $userOffset)) {
- $ret = sprintf(__('Today, %s',true), strftime("%H:%M", $date));
+ $ret = sprintf(__('Today, %s',true), Multibyte::strftime("%H:%M", $date));
} elseif ($this->wasYesterday($dateString, $userOffset)) {
- $ret = sprintf(__('Yesterday, %s',true), strftime("%H:%M", $date));
+ $ret = sprintf(__('Yesterday, %s',true), Multibyte::strftime("%H:%M", $date));
} else {
$format = $this->convertSpecifiers("%b %eS{$y}, %H:%M", $date);
- $ret = strftime($format, $date);
+ $ret = Multibyte::strftime($format, $date);
}
return $ret;
@@ -730,6 +733,6 @@ function i18nFormat($date, $format = null, $invalid = false, $userOffset = null)
$format = '%x';
}
$format = $this->convertSpecifiers($format, $date);
- return strftime($format, $date);
+ return Multibyte::strftime($format, $date);
}
}
15 cake/tests/cases/libs/view/helpers/time.test.php
View
@@ -751,6 +751,7 @@ function testI18nFormat() {
'locales' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'locale' . DS)
), true);
Configure::write('Config.language', 'time_test');
+
$time = strtotime('Thu Jan 14 13:59:28 2010');
$result = $this->Time->i18nFormat($time);
@@ -765,6 +766,20 @@ function testI18nFormat() {
$expected = 'Time is 01:59:28 PM, and date is 14/01/10';
$this->assertEqual($result, $expected);
+ $time = strtotime('Wed Jan 13 13:59:28 2010');
+
+ $result = $this->Time->i18nFormat($time);
+ $expected = '13/01/10';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Time->i18nFormat($time, '%c');
+ $expected = 'mié 13 ene 2010 13:59:28 ' . strftime('%Z', $time);
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Time->i18nFormat($time, 'Time is %r, and date is %x');
+ $expected = 'Time is 01:59:28 PM, and date is 13/01/10';
+ $this->assertEqual($result, $expected);
+
$result = $this->Time->i18nFormat('invalid date', '%x', 'Date invalid');
$expected = 'Date invalid';
$this->assertEqual($result, $expected);
Something went wrong with that request. Please try again.