From 96998d51f9788b0397c93b00a4ebfcfd4ed85c54 Mon Sep 17 00:00:00 2001 From: Edward Chernenko Date: Sun, 1 Jul 2018 05:10:56 +0300 Subject: [PATCH] Avoid arithmetics on localized number string ("0,04") in SpecialWatchlist In SpecialWatchlist::cutoffselector(), values like 1/24 or 6/24 are cast to string via strval(). However, in some locales (e.g. ru_RU.utf8) strval will return a localized form of the number, e.g. "0,04" instead of "0.04". This "0,04" is then used in arithmetic operations, where it's treated as 0, resulting in "0 hours" being shown instead of "1 hour", "2 hours", etc. Bug: T198501 Change-Id: Iaa4e6170b30a7bb9ce0f22d9d2cc4772b0faa3b8 (cherry picked from commit 6b240c699eb1e965dad3c51107566f1f27ed1887) --- includes/specials/SpecialWatchlist.php | 59 +++++++++++--------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index dda1dac3af..55a7f0391f 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -751,45 +751,36 @@ class SpecialWatchlist extends ChangesListSpecialPage { } function cutoffselector( $options ) { - // Cast everything to strings immediately, so that we know all of the values have the same - // precision, and can be compared with '==='. 2/24 has a few more decimal places than its - // default string representation, for example, and would confuse comparisons. - - // Misleadingly, the 'days' option supports hours too. - $days = array_map( 'strval', [ 1 / 24, 2 / 24, 6 / 24, 12 / 24, 1, 3, 7 ] ); - - $userWatchlistOption = (string)$this->getUser()->getOption( 'watchlistdays' ); - // add the user preference, if it isn't available already - if ( !in_array( $userWatchlistOption, $days ) && $userWatchlistOption !== '0' ) { - $days[] = $userWatchlistOption; - } - - $maxDays = (string)$this->maxDays; - // add the maximum possible value, if it isn't available already - if ( !in_array( $maxDays, $days ) ) { - $days[] = $maxDays; - } - - $selected = (string)$options['days']; + $selected = (float)$options['days']; if ( $selected <= 0 ) { - $selected = $maxDays; - } - - // add the currently selected value, if it isn't available already - if ( !in_array( $selected, $days ) ) { - $days[] = $selected; - } + $selected = $this->maxDays; + } + + $selectedHours = round( $selected * 24 ); + + $hours = array_unique( array_filter( [ + 1, + 2, + 6, + 12, + 24, + 72, + 168, + 24 * (float)$this->getUser()->getOption( 'watchlistdays', 0 ), + 24 * $this->maxDays, + $selectedHours + ] ) ); + asort( $hours ); - $select = new XmlSelect( 'days', 'days', $selected ); + $select = new XmlSelect( 'days', 'days', $selectedHours / 24 ); - asort( $days ); - foreach ( $days as $value ) { - if ( $value < 1 ) { - $name = $this->msg( 'hours' )->numParams( $value * 24 )->text(); + foreach ( $hours as $value ) { + if ( $value < 24 ) { + $name = $this->msg( 'hours' )->numParams( $value )->text(); } else { - $name = $this->msg( 'days' )->numParams( $value )->text(); + $name = $this->msg( 'days' )->numParams( $value / 24 )->text(); } - $select->addOption( $name, $value ); + $select->addOption( $name, $value / 24 ); } return $select->getHTML() . "\n
\n"; -- 2.20.1