function ut_main() { $locale_arr = array('en_US_CA'); $datetype_arr = array(IntlDateFormatter::FULL, IntlDateFormatter::LONG, IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, IntlDateFormatter::NONE); $res_str = ''; $text_arr = array("Sunday, September 18, 3039 4:06:40 PM PT", "Thursday, December 18, 1969 8:49:59 AM PST", "12/18/69 8:49 AM", "20111218 08:49 AM", "19691218 08:49 AM"); foreach ($text_arr as $text_entry) { $res_str .= "\n------------\n"; $res_str .= "\nInput text is : {$text_entry}"; $res_str .= "\n------------"; foreach ($locale_arr as $locale_entry) { $res_str .= "\nLocale is : {$locale_entry}"; $res_str .= "\n------------"; foreach ($datetype_arr as $datetype_entry) { $res_str .= "\ndatetype = {$datetype_entry} ,timetype ={$datetype_entry}"; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry); $pos = 0; $parsed = ut_datefmt_parse($fmt, $text_entry, $pos); if (intl_get_error_code() == U_ZERO_ERROR) { $res_str .= "\nParsed text is : {$parsed}; Position = {$pos}"; } else { $res_str .= "\nError while parsing as: '" . intl_get_error_message() . "'; Position = {$pos}"; } } } } $res_str .= "\n"; return $res_str; }
/** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $dateFormat = is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT; $timeFormat = \IntlDateFormatter::NONE; $calendar = \IntlDateFormatter::GREGORIAN; $pattern = is_string($options['format']) ? $options['format'] : null; if (!in_array($dateFormat, self::$acceptedFormats, true)) { throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.'); } if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) { throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); } if ('single_text' === $options['widget']) { $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer($options['model_timezone'], $options['view_timezone'], $dateFormat, $timeFormat, $calendar, $pattern)); } else { $yearOptions = $monthOptions = $dayOptions = array('error_bubbling' => true); $formatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, null, $calendar, $pattern); // new \intlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/bug.php?id=66323 if (!$formatter) { throw new InvalidOptionsException(intl_get_error_message(), intl_get_error_code()); } $formatter->setLenient(false); if ('choice' === $options['widget']) { // Only pass a subset of the options to children $yearOptions['choices'] = $this->formatTimestamps($formatter, '/y+/', $this->listYears($options['years'])); $yearOptions['choices_as_values'] = true; $yearOptions['placeholder'] = $options['placeholder']['year']; $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; $monthOptions['choices'] = $this->formatTimestamps($formatter, '/[M|L]+/', $this->listMonths($options['months'])); $monthOptions['choices_as_values'] = true; $monthOptions['placeholder'] = $options['placeholder']['month']; $monthOptions['choice_translation_domain'] = $options['choice_translation_domain']['month']; $dayOptions['choices'] = $this->formatTimestamps($formatter, '/d+/', $this->listDays($options['days'])); $dayOptions['choices_as_values'] = true; $dayOptions['placeholder'] = $options['placeholder']['day']; $dayOptions['choice_translation_domain'] = $options['choice_translation_domain']['day']; } // Append generic carry-along options foreach (array('required', 'translation_domain') as $passOpt) { $yearOptions[$passOpt] = $monthOptions[$passOpt] = $dayOptions[$passOpt] = $options[$passOpt]; } $builder->add('year', self::$widgets[$options['widget']], $yearOptions)->add('month', self::$widgets[$options['widget']], $monthOptions)->add('day', self::$widgets[$options['widget']], $dayOptions)->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day')))->setAttribute('formatter', $formatter); } if ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d'))); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer(new DateTimeToTimestampTransformer($options['model_timezone'], $options['model_timezone']))); } elseif ('array' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], array('year', 'month', 'day')))); } }
/** * Parse data string and convert to the \DateTime object. * * @param string $value * @param string|int|null $dateType * @param string|int|null $timeType * @param string|null $locale * @param string|null $timeZone * @param string|null $pattern * * @return \DateTime|false */ public function convert($value, $dateType = null, $timeType = null, $locale = null, $timeZone = null, $pattern = null) { if (!$locale) { $locale = $this->localeSettings->getLocale(); } if (!$timeZone) { $timeZone = $this->localeSettings->getTimeZone(); } if ($value) { $formatter = $this->getFormatter($dateType, $timeType, $locale, $timeZone, $pattern); $timestamp = $formatter->parse($value); if (intl_get_error_code() === 0) { return $this->getDateTime($timestamp); } } return false; }
function ut_main() { $res_str = ''; $forms = array(Normalizer::FORM_C, Normalizer::FORM_D, Normalizer::FORM_KC, Normalizer::FORM_KD, Normalizer::NONE); $forms_str = array(Normalizer::FORM_C => 'UNORM_FORM_C', Normalizer::FORM_D => 'UNORM_FORM_D', Normalizer::FORM_KC => 'UNORM_FORM_KC', Normalizer::FORM_KD => 'UNORM_FORM_KD', Normalizer::NONE => 'UNORM_NONE'); /* just make sure all the form constants are defined as in the api spec */ if (Normalizer::FORM_C != Normalizer::NFC || Normalizer::FORM_D != Normalizer::NFD || Normalizer::FORM_KC != Normalizer::NFKC || Normalizer::FORM_KD != Normalizer::NFKD || Normalizer::NONE == Normalizer::FORM_C) { $res_str .= "Invalid normalization form declarations!\n"; } $char_a_diaeresis = "ä"; // 'LATIN SMALL LETTER A WITH DIAERESIS' (U+00E4) $char_a_ring = "å"; // 'LATIN SMALL LETTER A WITH RING ABOVE' (U+00E5) $char_o_diaeresis = "ö"; // 'LATIN SMALL LETTER O WITH DIAERESIS' (U+00F6) $char_angstrom_sign = "Å"; // 'ANGSTROM SIGN' (U+212B) $char_A_ring = "Å"; // 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5) $char_ohm_sign = "Ω"; // 'OHM SIGN' (U+2126) $char_omega = "Ω"; // 'GREEK CAPITAL LETTER OMEGA' (U+03A9) $char_combining_ring_above = "̊"; // 'COMBINING RING ABOVE' (U+030A) $char_fi_ligature = "fi"; // 'LATIN SMALL LIGATURE FI' (U+FB01) $char_long_s_dot = "ẛ"; // 'LATIN SMALL LETTER LONG S WITH DOT ABOVE' (U+1E9B) $strs = array('ABC', $char_a_diaeresis . '||' . $char_a_ring . '||' . $char_o_diaeresis, $char_angstrom_sign . '||' . $char_A_ring . '||' . 'A' . $char_combining_ring_above, $char_ohm_sign . '||' . $char_omega, $char_fi_ligature, $char_long_s_dot); foreach ($forms as $form) { foreach ($strs as $str) { $str_norm = ut_norm_normalize($str, $form); $error_code = intl_get_error_code(); $error_message = intl_get_error_message(); $str_hex = urlencode($str); $str_norm_hex = urlencode($str_norm); $res_str .= "'{$str_hex}' normalized to form '{$forms_str[$form]}' is '{$str_norm_hex}'" . "\terror info: '{$error_message}' ({$error_code})\n" . ""; $is_norm = ut_norm_is_normalized($str, $form); $error_code = intl_get_error_code(); $error_message = intl_get_error_message(); $res_str .= "\t\tis in form '{$forms_str[$form]}'? = " . ($is_norm ? "yes" : "no") . "\terror info: '{$error_message}' ({$error_code})\n" . ""; } } return $res_str; }
/** * Transforms a localized date string/array into a normalized date. * * @param string|array $value Localized date string/array * @return DateTime Normalized date */ public function reverseTransform($value) { $inputTimezone = $this->getOption('input_timezone'); if (!is_string($value)) { throw new \InvalidArgumentException(sprintf('Expected argument of type string, %s given', gettype($value))); } $timestamp = $this->getIntlDateFormatter()->parse($value); if (intl_get_error_code() != 0) { throw new TransformationFailedException(intl_get_error_message()); } // read timestamp into DateTime object - the formatter delivers in UTC $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp)); if ($inputTimezone != 'UTC') { $dateTime->setTimezone(new \DateTimeZone($inputTimezone)); } return $dateTime; }
function ut_main() { $locale_arr = array('en_US_CA'); $datetype_arr = array(IntlDateFormatter::FULL, IntlDateFormatter::LONG, IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, IntlDateFormatter::NONE); $res_str = ''; $text_arr = array(array("Sunday, September 18, 2039 4:06:40 PM PT", IntlDateFormatter::FULL, IntlDateFormatter::FULL), array("Wednesday, December 17, 1969 6:40:00 PM PT", IntlDateFormatter::FULL, IntlDateFormatter::FULL), array("Thursday, December 18, 1969 8:49:59 PM PST", IntlDateFormatter::FULL, IntlDateFormatter::FULL), array("December 18, 1969 8:49:59 AM PST", IntlDateFormatter::LONG, IntlDateFormatter::FULL), array("12/18/69 8:49 AM", IntlDateFormatter::SHORT, IntlDateFormatter::SHORT), array("19691218 08:49 AM", IntlDateFormatter::SHORT, IntlDateFormatter::SHORT), array("Sunday, September 18, 2039 4:06:40 PM PT", IntlDateFormatter::FULL, IntlDateFormatter::NONE), array("Sunday, September 18, 2039 4:06:40 PM PT", IntlDateFormatter::FULL, IntlDateFormatter::SHORT), array("December 18, 1969 8:49:59 AM PST", IntlDateFormatter::LONG, IntlDateFormatter::NONE), array("December 18, 1969 8:49:59 AM PST", IntlDateFormatter::LONG, IntlDateFormatter::SHORT), array("12/18/69 8:49 AM", IntlDateFormatter::SHORT, IntlDateFormatter::LONG), array("19691218 08:49 AM", IntlDateFormatter::SHORT, IntlDateFormatter::LONG)); foreach ($text_arr as $text_entry) { $fmt = ut_datefmt_create('en_US_CA', $text_entry[1], $text_entry[2]); $parse_pos = 0; $parsed = ut_datefmt_parse($fmt, $text_entry[0], $parse_pos); $res_str .= "\nInput text : {$text_entry[0]} ; DF = {$text_entry[1]}; TF = {$text_entry[2]}"; if (intl_get_error_code() != U_ZERO_ERROR) { $res_str .= "\nError : " . intl_get_error_message(); } $res_str .= "\nParsed: {$parsed}; parse_pos : {$parse_pos}\n"; } return $res_str; }
/** * Formats the message with the help of php intl extension. * * @param string $locale * @param string $message * @param array(string=>mixed) $parameters * @return string * @throws CannotInstantiateFormatterException If the message pattern cannot be used. * @throws CannotFormatException If an error occurs during formatting. */ public function format($locale, $message, array $parameters) { if (empty($message)) { // Empty strings are not accepted as message pattern by the \MessageFormatter. return $message; } try { $formatter = new \MessageFormatter($locale, $message); } catch (\Exception $e) { throw new CannotInstantiateFormatterException($e->getMessage(), $e->getCode(), $e); } if (!$formatter) { throw new CannotInstantiateFormatterException(intl_get_error_message(), intl_get_error_code()); } $result = $formatter->format($parameters); if ($result === false) { throw new CannotFormatException($formatter->getErrorMessage(), $formatter->getErrorCode()); } return $result; }
/** * Transforms a localized date string/array into a normalized date. * * @param string|array $value Localized date string/array * @return DateTime Normalized date */ public function reverseTransform($value) { $inputTimezone = $this->getOption('input_timezone'); if (!is_string($value)) { throw new UnexpectedTypeException($value, 'string'); } if ('' === $value) { return null; } $timestamp = $this->getIntlDateFormatter()->parse($value); if (intl_get_error_code() != 0) { throw new TransformationFailedException(intl_get_error_message()); } // read timestamp into DateTime object - the formatter delivers in UTC $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp)); if ('UTC' != $inputTimezone) { $dateTime->setTimezone(new \DateTimeZone($inputTimezone)); } return $dateTime; }
/** * {@inheritdoc} */ public function format($value, array $options = array()) { if (null === $value) { return $options['null_value']; } if (!$value instanceof \DateTime) { throw FormatterException::invalidType($this, $value, 'DateTime instance'); } $dateTime = clone $value; if ('UTC' !== $options['time_zone']) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } $formatter = new \IntlDateFormatter(\Locale::getDefault(), $options['date_format'], $options['time_format'], $options['time_zone'], $options['calendar'], $options['pattern']); $formatter->setLenient(false); $value = $formatter->format((int) $dateTime->format('U')); if (intl_is_failure(intl_get_error_code())) { throw FormatterException::intlError($this, intl_get_error_message()); } $value = preg_replace('~GMT\\+00:00$~', 'GMT', $value); return $value; }
/** * Creates date time object from date string * * @param string $dateString * @param string|null $timeZone * @param string $format * @throws \Exception * @return \DateTime */ private function createDateTime($dateString, $timeZone = null, $format = 'yyyy-MM-dd') { $pattern = $format ? $format : null; if (!$timeZone) { $timeZone = date_default_timezone_get(); } $calendar = \IntlDateFormatter::GREGORIAN; $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, $timeZone, $calendar, $pattern); $intlDateFormatter->setLenient(false); $timestamp = $intlDateFormatter->parse($dateString); if (intl_get_error_code() != 0) { throw new \Exception(intl_get_error_message()); } // read timestamp into DateTime object - the formatter delivers in UTC $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp)); if ('UTC' !== $timeZone) { try { $dateTime->setTimezone(new \DateTimeZone($timeZone)); } catch (\Exception $e) { throw new \Exception($e->getMessage(), $e->getCode(), $e); } } return $dateTime; }
/** * Formats a message via [ICU message format](http://userguide.icu-project.org/formatparse/messages) * * It uses the PHP intl extension's [MessageFormatter](http://www.php.net/manual/en/class.messageformatter.php) * and works around some issues. * If PHP intl is not installed a fallback will be used that supports a subset of the ICU message format. * * @param string $pattern The pattern string to insert parameters into. * @param array $params The array of name value pairs to insert into the format string. * @param string $language The locale to use for formatting locale-dependent parts * @return string|boolean The formatted pattern string or `FALSE` if an error occurred */ public function format($pattern, $params, $language) { $this->_errorCode = 0; $this->_errorMessage = ''; if ($params === []) { return $pattern; } if (!class_exists('MessageFormatter', false)) { return $this->fallbackFormat($pattern, $params, $language); } if (version_compare(PHP_VERSION, '5.5.0', '<') || version_compare(INTL_ICU_VERSION, '4.8', '<')) { // replace named arguments $pattern = $this->replaceNamedArguments($pattern, $params, $newParams); $params = $newParams; } $formatter = new \MessageFormatter($language, $pattern); if ($formatter === null) { $this->_errorCode = intl_get_error_code(); $this->_errorMessage = "Message pattern is invalid: " . intl_get_error_message(); return false; } $result = $formatter->format($params); if ($result === false) { $this->_errorCode = $formatter->getErrorCode(); $this->_errorMessage = $formatter->getErrorMessage(); return false; } else { return $result; } }
/** * Formats a message via [ICU message format](http://userguide.icu-project.org/formatparse/messages) * * It uses the PHP intl extension's [MessageFormatter](http://www.php.net/manual/en/class.messageformatter.php) * and works around some issues. * If PHP intl is not installed a fallback will be used that supports a subset of the ICU message format. * * @param string $pattern The pattern string to insert parameters into. * @param array $params The array of name value pairs to insert into the format string. * @param string $language The locale to use for formatting locale-dependent parts * @return string|bool The formatted pattern string or `FALSE` if an error occurred */ public function format($pattern, $params, $language) { $this->_errorCode = 0; $this->_errorMessage = ''; if ($params === []) { return $pattern; } if (!class_exists('MessageFormatter', false)) { return $this->fallbackFormat($pattern, $params, $language); } // replace named arguments (https://github.com/yiisoft/yii2/issues/9678) $newParams = []; $pattern = $this->replaceNamedArguments($pattern, $params, $newParams); $params = $newParams; try { $formatter = new \MessageFormatter($language, $pattern); if ($formatter === null) { // formatter may be null in PHP 5.x $this->_errorCode = intl_get_error_code(); $this->_errorMessage = 'Message pattern is invalid: ' . intl_get_error_message(); return false; } } catch (\IntlException $e) { // IntlException is thrown since PHP 7 $this->_errorCode = $e->getCode(); $this->_errorMessage = 'Message pattern is invalid: ' . $e->getMessage(); return false; } catch (\Exception $e) { // Exception is thrown by HHVM $this->_errorCode = $e->getCode(); $this->_errorMessage = 'Message pattern is invalid: ' . $e->getMessage(); return false; } $result = $formatter->format($params); if ($result === false) { $this->_errorCode = $formatter->getErrorCode(); $this->_errorMessage = $formatter->getErrorMessage(); return false; } else { return $result; } }
/** * @dataProvider parseProvider */ public function testParseIntl($value, $expected, $message = '') { $this->skipIfIntlExtensionIsNotLoaded(); $this->skipIfICUVersionIsTooOld(); $formatter = $this->getIntlFormatterWithDecimalStyle(); $parsedValue = $formatter->parse($value, \NumberFormatter::TYPE_DOUBLE); $this->assertSame($expected, $parsedValue, $message); if ($expected === false) { $errorCode = StubIntl::U_PARSE_ERROR; $errorMessage = 'Number parsing failed: U_PARSE_ERROR'; } else { $errorCode = StubIntl::U_ZERO_ERROR; $errorMessage = 'U_ZERO_ERROR'; } $this->assertSame($errorMessage, intl_get_error_message()); $this->assertSame($errorCode, intl_get_error_code()); $this->assertSame($errorCode > 0, intl_is_failure(intl_get_error_code())); $this->assertSame($errorMessage, $formatter->getErrorMessage()); $this->assertSame($errorCode, $formatter->getErrorCode()); $this->assertSame($errorCode > 0, intl_is_failure($formatter->getErrorCode())); }
function ut_main() { $timezone = 'GMT+05:00'; $locale_arr = array('en_US'); $datetype_arr = array(IntlDateFormatter::FULL, IntlDateFormatter::LONG, IntlDateFormatter::MEDIUM); $res_str = ''; $time_arr = array(0, -1200000, 1200000, 2200000000, -2200000000, 90099999, 3600, -3600); $localtime_arr1 = array('tm_sec' => 24, 'tm_min' => 3, 'tm_hour' => 19, 'tm_mday' => 3, 'tm_mon' => 3, 'tm_year' => 105); $localtime_arr2 = array('tm_sec' => 21, 'tm_min' => 5, 'tm_hour' => 7, 'tm_mday' => 13, 'tm_mon' => 7, 'tm_year' => 205); $localtime_arr3 = array('tm_sec' => 11, 'tm_min' => 13, 'tm_hour' => 0, 'tm_mday' => 17, 'tm_mon' => 11, 'tm_year' => -5); $localtime_arr = array($localtime_arr1, $localtime_arr2, $localtime_arr3); //Test format and parse with a timestamp : long foreach ($time_arr as $timestamp_entry) { $res_str .= "\n------------\n"; $res_str .= "\nInput timestamp is : {$timestamp_entry}"; $res_str .= "\n------------\n"; foreach ($locale_arr as $locale_entry) { foreach ($datetype_arr as $datetype_entry) { $res_str .= "\nIntlDateFormatter locale= {$locale_entry} ,datetype = {$datetype_entry} ,timetype ={$datetype_entry} "; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone); $formatted = ut_datefmt_format($fmt, $timestamp_entry); $res_str .= "\nFormatted timestamp is : {$formatted}"; $parsed = ut_datefmt_parse($fmt, $formatted); if (intl_get_error_code() == U_ZERO_ERROR) { $res_str .= "\nParsed timestamp is : {$parsed}"; } else { $res_str .= "\nError while parsing as: '" . intl_get_error_message() . "'"; } } } } //Test format and parse with a localtime :array foreach ($localtime_arr as $localtime_entry) { $res_str .= "\n------------\n"; $res_str .= "\nInput localtime is : "; foreach ($localtime_entry as $key => $value) { $res_str .= "{$key} : '{$value}' , "; } $res_str .= "\n------------\n"; foreach ($locale_arr as $locale_entry) { foreach ($datetype_arr as $datetype_entry) { $res_str .= "\nIntlDateFormatter locale= {$locale_entry} ,datetype = {$datetype_entry} ,timetype ={$datetype_entry} "; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone); $formatted1 = ut_datefmt_format($fmt, $localtime_entry); if (intl_get_error_code() == U_ZERO_ERROR) { $res_str .= "\nFormatted localtime_array is : {$formatted1}"; } else { $res_str .= "\nError while formatting as: '" . intl_get_error_message() . "'"; } //Parsing $parsed_arr = ut_datefmt_localtime($fmt, $formatted1); if ($parsed_arr) { $res_str .= "\nParsed array is: "; foreach ($parsed_arr as $key => $value) { $res_str .= "{$key} : '{$value}' , "; } } /* else{ //$res_str .= "No values found from LocaleTime parsing."; $res_str .= "\tError : '".intl_get_error_message()."'"; } */ } } } return $res_str; }
protected function getIntlErrorCode() { return intl_get_error_code(); }
function renderPage() { $LINKSDB = new LinkDB($GLOBALS['config']['DATASTORE'], isLoggedIn(), $GLOBALS['config']['HIDE_PUBLIC_LINKS'], $GLOBALS['redirector'], $GLOBALS['config']['REDIRECTOR_URLENCODE']); $updater = new Updater(read_updates_file($GLOBALS['config']['UPDATES_FILE']), $GLOBALS, $LINKSDB, isLoggedIn()); try { $newUpdates = $updater->update(); if (!empty($newUpdates)) { write_updates_file($GLOBALS['config']['UPDATES_FILE'], $updater->getDoneUpdates()); } } catch (Exception $e) { die($e->getMessage()); } $PAGE = new PageBuilder(); $PAGE->assign('linkcount', count($LINKSDB)); $PAGE->assign('privateLinkcount', count_private($LINKSDB)); // Determine which page will be rendered. $query = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''; $targetPage = Router::findPage($query, $_GET, isLoggedIn()); // Call plugin hooks for header, footer and includes, specifying which page will be rendered. // Then assign generated data to RainTPL. $common_hooks = array('includes', 'header', 'footer'); $pluginManager = PluginManager::getInstance(); foreach ($common_hooks as $name) { $plugin_data = array(); $pluginManager->executeHooks('render_' . $name, $plugin_data, array('target' => $targetPage, 'loggedin' => isLoggedIn())); $PAGE->assign('plugins_' . $name, $plugin_data); } // -------- Display login form. if ($targetPage == Router::$PAGE_LOGIN) { if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli $token = ''; if (ban_canLogin()) { $token = getToken(); } // Do not waste token generation if not useful. $PAGE->assign('token', $token); if (isset($_GET['username'])) { $PAGE->assign('username', escape($_GET['username'])); } $PAGE->assign('returnurl', isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''); $PAGE->renderPage('loginform'); exit; } // -------- User wants to logout. if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) { invalidateCaches($GLOBALS['config']['PAGECACHE']); logout(); header('Location: ?'); exit; } // -------- Picture wall if ($targetPage == Router::$PAGE_PICWALL) { // Optionally filter the results: $links = $LINKSDB->filterSearch($_GET); $linksToDisplay = array(); // Get only links which have a thumbnail. foreach ($links as $link) { $permalink = '?' . escape(smallhash($link['linkdate'])); $thumb = lazyThumbnail($link['url'], $permalink); if ($thumb != '') { $link['thumbnail'] = $thumb; // Thumbnail HTML code. $linksToDisplay[] = $link; // Add to array. } } $data = array('linksToDisplay' => $linksToDisplay); $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => isLoggedIn())); foreach ($data as $key => $value) { $PAGE->assign($key, $value); } $PAGE->renderPage('picwall'); exit; } // -------- Tag cloud if ($targetPage == Router::$PAGE_TAGCLOUD) { $tags = $LINKSDB->allTags(); // We sort tags alphabetically, then choose a font size according to count. // First, find max value. $maxcount = 0; foreach ($tags as $value) { $maxcount = max($maxcount, $value); } // Sort tags alphabetically: case insensitive, support locale if avalaible. uksort($tags, function ($a, $b) { // Collator is part of PHP intl. if (class_exists('Collator')) { $c = new Collator(setlocale(LC_COLLATE, 0)); if (!intl_is_failure(intl_get_error_code())) { return $c->compare($a, $b); } } return strcasecmp($a, $b); }); $tagList = array(); foreach ($tags as $key => $value) { // Tag font size scaling: // default 15 and 30 logarithm bases affect scaling, // 22 and 6 are arbitrary font sizes for max and min sizes. $size = log($value, 15) / log($maxcount, 30) * 2.2 + 0.8; $tagList[$key] = array('count' => $value, 'size' => number_format($size, 2, '.', '')); } $data = array('tags' => $tagList); $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); foreach ($data as $key => $value) { $PAGE->assign($key, $value); } $PAGE->renderPage('tagcloud'); exit; } // Daily page. if ($targetPage == Router::$PAGE_DAILY) { showDaily($PAGE, $LINKSDB); } // ATOM and RSS feed. if ($targetPage == Router::$PAGE_FEED_ATOM || $targetPage == Router::$PAGE_FEED_RSS) { $feedType = $targetPage == Router::$PAGE_FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM; header('Content-Type: application/' . $feedType . '+xml; charset=utf-8'); // Cache system $query = $_SERVER['QUERY_STRING']; $cache = new CachedPage($GLOBALS['config']['PAGECACHE'], page_url($_SERVER), startsWith($query, 'do=' . $targetPage) && !isLoggedIn()); $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } // Generate data. $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); $feedGenerator->setHideDates($GLOBALS['config']['HIDE_TIMESTAMPS'] && !isLoggedIn()); $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']); if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { $feedGenerator->setPubsubhubUrl($GLOBALS['config']['PUBSUBHUB_URL']); } $data = $feedGenerator->buildData(); // Process plugin hook. $pluginManager = PluginManager::getInstance(); $pluginManager->executeHooks('render_feed', $data, array('loggedin' => isLoggedIn(), 'target' => $targetPage)); // Render the template. $PAGE->assignAll($data); $PAGE->renderPage('feed.' . $feedType); $cache->cache(ob_get_contents()); ob_end_flush(); exit; } // Display openseach plugin (XML) if ($targetPage == Router::$PAGE_OPENSEARCH) { header('Content-Type: application/xml; charset=utf-8'); $PAGE->assign('serverurl', index_url($_SERVER)); $PAGE->renderPage('opensearch'); exit; } // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) if (isset($_GET['addtag'])) { // Get previous URL (http_referer) and add the tag to the searchtags parameters in query. if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags=' . urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); // Prevent redirection loop if (isset($params['addtag'])) { unset($params['addtag']); } // Check if this tag is already in the search query and ignore it if it is. // Each tag is always separated by a space if (isset($params['searchtags'])) { $current_tags = explode(' ', $params['searchtags']); } else { $current_tags = array(); } $addtag = true; foreach ($current_tags as $value) { if ($value === $_GET['addtag']) { $addtag = false; break; } } // Append the tag if necessary if (empty($params['searchtags'])) { $params['searchtags'] = trim($_GET['addtag']); } else { if ($addtag) { $params['searchtags'] = trim($params['searchtags']) . ' ' . trim($_GET['addtag']); } } unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) header('Location: ?' . http_build_query($params)); exit; } // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) if (isset($_GET['removetag'])) { // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); // Prevent redirection loop if (isset($params['removetag'])) { unset($params['removetag']); } if (isset($params['searchtags'])) { $tags = explode(' ', $params['searchtags']); // Remove value from array $tags. $tags = array_diff($tags, array($_GET['removetag'])); $params['searchtags'] = implode(' ', $tags); if (empty($params['searchtags'])) { unset($params['searchtags']); } unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) } header('Location: ?' . http_build_query($params)); exit; } // -------- User wants to change the number of links per page (linksperpage=...) if (isset($_GET['linksperpage'])) { if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE'] = abs(intval($_GET['linksperpage'])); } header('Location: ' . generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage'))); exit; } // -------- User wants to see only private links (toggle) if (isset($_GET['privateonly'])) { if (empty($_SESSION['privateonly'])) { $_SESSION['privateonly'] = 1; // See only private links } else { unset($_SESSION['privateonly']); // See all links } header('Location: ' . generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly'))); exit; } // -------- Handle other actions allowed for non-logged in users: if (!isLoggedIn()) { // User tries to post new link but is not logged in: // Show login screen, then redirect to ?post=... if (isset($_GET['post'])) { header('Location: ?do=login&post=' . urlencode($_GET['post']) . (!empty($_GET['title']) ? '&title=' . urlencode($_GET['title']) : '') . (!empty($_GET['description']) ? '&description=' . urlencode($_GET['description']) : '') . (!empty($_GET['source']) ? '&source=' . urlencode($_GET['source']) : '')); // Redirect to login page, then back to post link. exit; } showLinkList($PAGE, $LINKSDB); if (isset($_GET['edit_link'])) { header('Location: ?do=login&edit_link=' . escape($_GET['edit_link'])); exit; } exit; // Never remove this one! All operations below are reserved for logged in user. } // -------- All other functions are reserved for the registered user: // -------- Display the Tools menu if requested (import/export/bookmarklet...) if ($targetPage == Router::$PAGE_TOOLS) { $data = array('pageabsaddr' => index_url($_SERVER)); $pluginManager->executeHooks('render_tools', $data); foreach ($data as $key => $value) { $PAGE->assign($key, $value); } $PAGE->renderPage('tools'); exit; } // -------- User wants to change his/her password. if ($targetPage == Router::$PAGE_CHANGEPASSWORD) { if ($GLOBALS['config']['OPEN_SHAARLI']) { die('You are not supposed to change a password on an Open Shaarli.'); } if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) { if (!tokenOk($_POST['token'])) { die('Wrong token.'); } // Go away! // Make sure old password is correct. $oldhash = sha1($_POST['oldpassword'] . $GLOBALS['login'] . $GLOBALS['salt']); if ($oldhash != $GLOBALS['hash']) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } // Save new password $GLOBALS['salt'] = sha1(uniqid('', true) . '_' . mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'] . $GLOBALS['login'] . $GLOBALS['salt']); try { writeConfig($GLOBALS, isLoggedIn()); } catch (Exception $e) { error_log('ERROR while writing config file after changing password.' . PHP_EOL . $e->getMessage()); // TODO: do not handle exceptions/errors in JS. echo '<script>alert("' . $e->getMessage() . '");document.location=\'?do=tools\';</script>'; exit; } echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>'; exit; } else { $PAGE->assign('token', getToken()); $PAGE->renderPage('changepassword'); exit; } } // -------- User wants to change configuration if ($targetPage == Router::$PAGE_CONFIGURE) { if (!empty($_POST['title'])) { if (!tokenOk($_POST['token'])) { die('Wrong token.'); // Go away! } $tz = 'UTC'; if (!empty($_POST['continent']) && !empty($_POST['city']) && isTimeZoneValid($_POST['continent'], $_POST['city'])) { $tz = $_POST['continent'] . '/' . $_POST['city']; } $GLOBALS['timezone'] = $tz; $GLOBALS['title'] = $_POST['title']; $GLOBALS['titleLink'] = $_POST['titleLink']; $GLOBALS['redirector'] = $_POST['redirector']; $GLOBALS['disablesessionprotection'] = !empty($_POST['disablesessionprotection']); $GLOBALS['privateLinkByDefault'] = !empty($_POST['privateLinkByDefault']); $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = !empty($_POST['enableRssPermalinks']); $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); try { writeConfig($GLOBALS, isLoggedIn()); } catch (Exception $e) { error_log('ERROR while writing config file after configuration update.' . PHP_EOL . $e->getMessage()); // TODO: do not handle exceptions/errors in JS. echo '<script>alert("' . $e->getMessage() . '");document.location=\'?do=tools\';</script>'; exit; } echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; exit; } else { $PAGE->assign('token', getToken()); $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title']); $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); list($timezone_form, $timezone_js) = generateTimeZoneForm($GLOBALS['timezone']); $PAGE->assign('timezone_form', $timezone_form); $PAGE->assign('timezone_js', $timezone_js); $PAGE->renderPage('configure'); exit; } } // -------- User wants to rename a tag or delete it if ($targetPage == Router::$PAGE_CHANGETAG) { if (empty($_POST['fromtag']) || empty($_POST['totag']) && isset($_POST['renametag'])) { $PAGE->assign('token', getToken()); $PAGE->assign('tags', $LINKSDB->allTags()); $PAGE->renderPage('changetag'); exit; } if (!tokenOk($_POST['token'])) { die('Wrong token.'); } // Delete a tag: if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { $needle = trim($_POST['fromtag']); // True for case-sensitive tag search. $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); foreach ($linksToAlter as $key => $value) { $tags = explode(' ', trim($value['tags'])); unset($tags[array_search($needle, $tags)]); // Remove tag. $value['tags'] = trim(implode(' ', $tags)); $LINKSDB[$key] = $value; } $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); echo '<script>alert("Tag was removed from ' . count($linksToAlter) . ' links.");document.location=\'?\';</script>'; exit; } // Rename a tag: if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { $needle = trim($_POST['fromtag']); // True for case-sensitive tag search. $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); foreach ($linksToAlter as $key => $value) { $tags = explode(' ', trim($value['tags'])); $tags[array_search($needle, $tags)] = trim($_POST['totag']); // Replace tags value. $value['tags'] = trim(implode(' ', $tags)); $LINKSDB[$key] = $value; } $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk. echo '<script>alert("Tag was renamed in ' . count($linksToAlter) . ' links.");document.location=\'?searchtags=' . urlencode($_POST['totag']) . '\';</script>'; exit; } } // -------- User wants to add a link without using the bookmarklet: Show form. if ($targetPage == Router::$PAGE_ADDLINK) { $PAGE->renderPage('addlink'); exit; } // -------- User clicked the "Save" button when editing a link: Save link to database. if (isset($_POST['save_edit'])) { // Go away! if (!tokenOk($_POST['token'])) { die('Wrong token.'); } // Remove multiple spaces. $tags = trim(preg_replace('/\\s\\s+/', ' ', $_POST['lf_tags'])); // Remove first '-' char in tags. $tags = preg_replace('/(^| )\\-/', '$1', $tags); // Remove duplicates. $tags = implode(' ', array_unique(explode(' ', $tags))); $linkdate = $_POST['lf_linkdate']; $url = trim($_POST['lf_url']); if (!startsWith($url, 'http:') && !startsWith($url, 'https:') && !startsWith($url, 'ftp:') && !startsWith($url, 'magnet:') && !startsWith($url, '?') && !startsWith($url, 'javascript:')) { $url = 'http://' . $url; } $link = array('title' => trim($_POST['lf_title']), 'url' => $url, 'description' => $_POST['lf_description'], 'private' => isset($_POST['lf_private']) ? 1 : 0, 'linkdate' => $linkdate, 'tags' => str_replace(',', ' ', $tags)); // If title is empty, use the URL as title. if ($link['title'] == '') { $link['title'] = $link['url']; } $pluginManager->executeHooks('save_link', $link); $LINKSDB[$linkdate] = $link; $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); pubsubhub(); // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && ($_GET['source'] == 'bookmarklet' || $_GET['source'] == 'firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } $returnurl = !empty($_POST['returnurl']) ? $_POST['returnurl'] : '?'; $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); // Scroll to the link which has been edited. $location .= '#' . smallHash($_POST['lf_linkdate']); // After saving the link, redirect to the page the user was on. header('Location: ' . $location); exit; } // -------- User clicked the "Cancel" button when editing a link. if (isset($_POST['cancel_edit'])) { // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && ($_GET['source'] == 'bookmarklet' || $_GET['source'] == 'firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } $returnurl = isset($_POST['returnurl']) ? $_POST['returnurl'] : '?'; $returnurl .= '#' . smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link')); header('Location: ' . $returnurl); // After canceling, redirect to the page the user was on. exit; } // -------- User clicked the "Delete" button when editing a link: Delete link from database. if (isset($_POST['delete_link'])) { if (!tokenOk($_POST['token'])) { die('Wrong token.'); } // We do not need to ask for confirmation: // - confirmation is handled by JavaScript // - we are protected from XSRF by the token. $linkdate = $_POST['lf_linkdate']; $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); unset($LINKSDB[$linkdate]); $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // save to disk // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && ($_GET['source'] == 'bookmarklet' || $_GET['source'] == 'firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } // Pick where we're going to redirect // ============================================================= // Basically, we can't redirect to where we were previously if it was a permalink // or an edit_link, because it would 404. // Cases: // - / : nothing in $_GET, redirect to self // - /?page : redirect to self // - /?searchterm : redirect to self (there might be other links) // - /?searchtags : redirect to self // - /permalink : redirect to / (the link does not exist anymore) // - /?edit_link : redirect to / (the link does not exist anymore) // PHP treats the permalink as a $_GET variable, so we need to check if every condition for self // redirect is not satisfied, and only then redirect to / $location = "?"; // Self redirection if (count($_GET) == 0 || isset($_GET['page']) || isset($_GET['searchterm']) || isset($_GET['searchtags'])) { if (isset($_POST['returnurl'])) { $location = $_POST['returnurl']; // Handle redirects given by the form } else { $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link')); } } header('Location: ' . $location); // After deleting the link, redirect to appropriate location exit; } // -------- User clicked the "EDIT" button on a link: Display link edit form. if (isset($_GET['edit_link'])) { $link = $LINKSDB[$_GET['edit_link']]; // Read database if (!$link) { header('Location: ?'); exit; } // Link not found in database. $data = array('link' => $link, 'link_is_new' => false, 'token' => getToken(), 'http_referer' => isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : '', 'tags' => $LINKSDB->allTags()); $pluginManager->executeHooks('render_editlink', $data); foreach ($data as $key => $value) { $PAGE->assign($key, $value); } $PAGE->renderPage('editlink'); exit; } // -------- User want to post a new link: Display link edit form. if (isset($_GET['post'])) { $url = cleanup_url($_GET['post']); $link_is_new = false; // Check if URL is not already in database (in this case, we will edit the existing link) $link = $LINKSDB->getLinkFromUrl($url); if (!$link) { $link_is_new = true; $linkdate = strval(date('Ymd_His')); // Get title if it was provided in URL (by the bookmarklet). $title = empty($_GET['title']) ? '' : escape($_GET['title']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] $description = empty($_GET['description']) ? '' : escape($_GET['description']); $tags = empty($_GET['tags']) ? '' : escape($_GET['tags']); $private = !empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0; // If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.) if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { // Short timeout to keep the application responsive list($headers, $content) = get_http_response($url, 4); if (strpos($headers[0], '200 OK') !== false) { // Retrieve charset. $charset = get_charset($headers, $content); // Extract title. $title = html_extract_title($content); // Re-encode title in utf-8 if necessary. if (!empty($title) && strtolower($charset) != 'utf-8') { $title = mb_convert_encoding($title, 'utf-8', $charset); } } } if ($url == '') { $url = '?' . smallHash($linkdate); $title = 'Note: '; } $url = escape($url); $title = escape($title); $link = array('linkdate' => $linkdate, 'title' => $title, 'url' => $url, 'description' => $description, 'tags' => $tags, 'private' => $private); } $data = array('link' => $link, 'link_is_new' => $link_is_new, 'token' => getToken(), 'http_referer' => isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : '', 'source' => isset($_GET['source']) ? $_GET['source'] : '', 'tags' => $LINKSDB->allTags()); $pluginManager->executeHooks('render_editlink', $data); foreach ($data as $key => $value) { $PAGE->assign($key, $value); } $PAGE->renderPage('editlink'); exit; } if ($targetPage == Router::$PAGE_EXPORT) { // Export links as a Netscape Bookmarks file if (empty($_GET['selection'])) { $PAGE->renderPage('export'); exit; } // export as bookmarks_(all|private|public)_YYYYmmdd_HHMMSS.html $selection = $_GET['selection']; if (isset($_GET['prepend_note_url'])) { $prependNoteUrl = $_GET['prepend_note_url']; } else { $prependNoteUrl = false; } try { $PAGE->assign('links', NetscapeBookmarkUtils::filterAndFormat($LINKSDB, $selection, $prependNoteUrl, index_url($_SERVER))); } catch (Exception $exc) { header('Content-Type: text/plain; charset=utf-8'); echo $exc->getMessage(); exit; } $now = new DateTime(); header('Content-Type: text/html; charset=utf-8'); header('Content-disposition: attachment; filename=bookmarks_' . $selection . '_' . $now->format(LinkDB::LINK_DATE_FORMAT) . '.html'); $PAGE->assign('date', $now->format(DateTime::RFC822)); $PAGE->assign('eol', PHP_EOL); $PAGE->assign('selection', $selection); $PAGE->renderPage('export.bookmarks'); exit; } // -------- User is uploading a file for import if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=upload')) { // If file is too big, some form field may be missing. if (!isset($_POST['token']) || !isset($_FILES) || isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { $returnurl = empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER']; echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept (' . getMaxFileSize() . ' bytes). Please upload in smaller chunks.");document.location=\'' . escape($returnurl) . '\';</script>'; exit; } if (!tokenOk($_POST['token'])) { die('Wrong token.'); } importFile($LINKSDB); exit; } // -------- Show upload/import dialog: if ($targetPage == Router::$PAGE_IMPORT) { $PAGE->assign('token', getToken()); $PAGE->assign('maxfilesize', getMaxFileSize()); $PAGE->renderPage('import'); exit; } // Plugin administration page if ($targetPage == Router::$PAGE_PLUGINSADMIN) { $pluginMeta = $pluginManager->getPluginsMeta(); // Split plugins into 2 arrays: ordered enabled plugins and disabled. $enabledPlugins = array_filter($pluginMeta, function ($v) { return $v['order'] !== false; }); // Load parameters. $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $GLOBALS['plugins']); uasort($enabledPlugins, function ($a, $b) { return $a['order'] - $b['order']; }); $disabledPlugins = array_filter($pluginMeta, function ($v) { return $v['order'] === false; }); $PAGE->assign('enabledPlugins', $enabledPlugins); $PAGE->assign('disabledPlugins', $disabledPlugins); $PAGE->renderPage('pluginsadmin'); exit; } // Plugin administration form action if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) { try { if (isset($_POST['parameters_form'])) { unset($_POST['parameters_form']); foreach ($_POST as $param => $value) { $GLOBALS['plugins'][$param] = escape($value); } } else { $GLOBALS['config']['ENABLED_PLUGINS'] = save_plugin_config($_POST); } writeConfig($GLOBALS, isLoggedIn()); } catch (Exception $e) { error_log('ERROR while saving plugin configuration:.' . PHP_EOL . $e->getMessage()); // TODO: do not handle exceptions/errors in JS. echo '<script>alert("' . $e->getMessage() . '");document.location=\'?do=' . Router::$PAGE_PLUGINSADMIN . '\';</script>'; exit; } header('Location: ?do=' . Router::$PAGE_PLUGINSADMIN); exit; } // -------- Otherwise, simply display search form and links: showLinkList($PAGE, $LINKSDB); exit; }
var_dump(idn_to_ascii("-foo.com", 0, INTL_IDNA_VARIANT_UTS46)); echo "\n", "empty domain:", "\n"; var_dump(idn_to_ascii("", 0, INTL_IDNA_VARIANT_UTS46, $info)); var_dump($info); var_dump($info["errors"] == IDNA_ERROR_EMPTY_LABEL); echo "\n", "domain too long (max allowed 253, trailing hyphen ignored):", "\n"; $result = idn_to_ascii(str_repeat("a.", 126) . "aa", 0, INTL_IDNA_VARIANT_UTS46, $info); var_dump($result); var_dump($info); var_dump($info["errors"] == IDNA_ERROR_DOMAIN_NAME_TOO_LONG); echo "\n", "buffer overflow:", "\n"; $result = idn_to_ascii(str_repeat("a", 2048), 0, INTL_IDNA_VARIANT_UTS46, $info); var_dump($result); var_dump($info); var_dump(intl_get_error_code() == U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR); echo "\n", "BiDi and CONTEXTJ errors:", "\n"; $result = idn_to_ascii(u("\\u0644\\u200C"), IDNA_NONTRANSITIONAL_TO_ASCII | IDNA_CHECK_BIDI | IDNA_CHECK_CONTEXTJ, INTL_IDNA_VARIANT_UTS46, $info); var_dump($result); var_dump($info); var_dump($info["errors"] == (IDNA_ERROR_BIDI | IDNA_ERROR_CONTEXTJ)); echo "\n", "reverse, invalid Punycode:", "\n"; $result = idn_to_utf8("xn--0", 0, INTL_IDNA_VARIANT_UTS46, $info); var_dump($result); var_dump($info); var_dump($info["errors"] == IDNA_ERROR_PUNYCODE); echo "\n", "reverse, buffer overflow:", "\n"; $result = idn_to_utf8(str_repeat("a", 2048), 0, INTL_IDNA_VARIANT_UTS46, $info); var_dump($result); var_dump($info); var_dump(intl_get_error_code() == U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR);
/** * Does the actual formatting using the MessageFormatter class * * @param string $locale The locale in which the message is presented. * @param string|array $message The message to be translated * @param array $vars The list of values to interpolate in the message * @return string The formatted message * @throws \Aura\Intl\Exception\CannotInstantiateFormatter if any error occurred * while parsing the message * @throws \Aura\Intl\Exception\CannotFormat If any error related to the passed * variables is found */ protected function _formatMessage($locale, $message, $vars) { // Using procedural style as it showed twice as fast as // its counterpart in PHP 5.5 $result = MessageFormatter::formatMessage($locale, $message, $vars); if ($result === false) { // The user might be interested in what went wrong, so replay the // previous action using the object oriented style to figure out $formatter = new MessageFormatter($locale, $message); if (!$formatter) { throw new Exception\CannotInstantiateFormatter(intl_get_error_message(), intl_get_error_code()); } $formatter->format($vars); throw new Exception\CannotFormat($formatter->getErrorMessage(), $formatter->getErrorCode()); } return $result; }
/** * * Format the message with the help of php intl extension * * @param string $locale * @param string $string * @param array $tokens_values * @return string * @throws Exception */ public function format($locale, $string, array $tokens_values) { // extract tokens and retain sequential positions $tokens = []; $i = 0; // opening brace, followed by the token word characters, // followed by any non-token word character $regex = '/(\\{)([A-Za-z0-9_]+)([\\,\\}])/m'; preg_match_all($regex, $string, $matches, PREG_SET_ORDER); foreach ($matches as $match) { // the token name $key = $match[2]; if (!isset($tokens[$key])) { $tokens[$key] = $i; $num = $i; $i++; } else { $num = $tokens[$key]; } // replace just the first occurence; // other occurrences will get replaced later. $string = preg_replace("/{$match['0']}/", '{' . $num . $match[3], $string, 1); } $values = []; foreach ($tokens as $token => $i) { if (!isset($tokens_values[$token])) { continue; } $value = $tokens_values[$token]; // convert an array to a CSV string if (is_array($value)) { $value = '"' . implode('", "', $value) . '"'; } $values[$i] = $value; } $formatter = new MessageFormatter($locale, $string); if (!$formatter) { throw new Exception\CannotInstantiateFormatter(intl_get_error_message(), intl_get_error_code()); } $result = $formatter->format($values); if ($result === false) { throw new Exception\CannotFormat($formatter->getErrorMessage(), $formatter->getErrorCode()); } return $result; }
/** * Ensures that a collator is available and created * * @return bool Returns true if collation is available and ready */ protected static function ensure_collator_available() { $locale = get_string('locale', 'langconfig'); if (is_null(self::$collator) || $locale != self::$locale) { self::$collator = false; self::$locale = $locale; if (class_exists('Collator', false)) { $collator = new Collator($locale); if (!empty($collator) && $collator instanceof Collator) { // Check for non fatal error messages. This has to be done immediately // after instantiation as any further calls to collation will cause // it to reset to 0 again (or another error code if one occurred) $errorcode = $collator->getErrorCode(); $errormessage = $collator->getErrorMessage(); // Check for an error code, 0 means no error occurred if ($errorcode !== 0) { // Get the actual locale being used, e.g. en, he, zh $localeinuse = $collator->getLocale(Locale::ACTUAL_LOCALE); // Check for the common fallback warning error codes. If any of the two // following errors occurred, there is normally little to worry about: // * U_USING_FALLBACK_WARNING (-128) indicates that a fall back locale was // used. For example, 'de_CH' was requested, but nothing was found // there, so 'de' was used. // * U_USING_DEFAULT_WARNING (-127) indicates that the default locale // data was used; neither the requested locale nor any of its fall // back locales could be found. For example, 'pt' was requested, but // UCA was used (Unicode Collation Algorithm http://unicode.org/reports/tr10/). // See http://www.icu-project.org/apiref/icu4c/classicu_1_1ResourceBundle.html if ($errorcode === -127 || $errorcode === -128) { // Check if the locale in use is UCA default one ('root') or // if it is anything like the locale we asked for if ($localeinuse !== 'root' && strpos($locale, $localeinuse) !== 0) { // The locale we asked for is completely different to the locale // we have received, let the user know via debugging debugging('Locale warning (not fatal) ' . $errormessage . ': ' . 'Requested locale "' . $locale . '" not found, locale "' . $localeinuse . '" used instead. ' . 'The most specific locale supported by ICU relatively to the requested locale is "' . $collator->getLocale(Locale::VALID_LOCALE) . '".'); } else { // Nothing to do here, this is expected! // The Moodle locale setting isn't what the collator expected but // it is smart enough to match the first characters of our locale // to find the correct locale or to use UCA collation } } else { // We've received some other sort of non fatal warning - let the // user know about it via debugging. debugging('Problem with locale: ' . $errormessage . '. ' . 'Requested locale: "' . $locale . '", actual locale "' . $localeinuse . '". ' . 'The most specific locale supported by ICU relatively to the requested locale is "' . $collator->getLocale(Locale::VALID_LOCALE) . '".'); } } // Store the collator object now that we can be sure it is in a workable condition self::$collator = $collator; } else { // Fatal error while trying to instantiate the collator... something went wrong debugging('Error instantiating collator for locale: "' . $locale . '", with error [' . intl_get_error_code() . '] ' . intl_get_error_message($collator)); } } } return self::$collator instanceof Collator; }
/** * Ensures that a collator is available and created * * @return bool Returns true if collation is available and ready */ protected static function ensure_collator_available() { global $CFG; $locale = get_string('locale', 'langconfig'); if (is_null(self::$collator) || $locale != self::$locale) { self::$collator = false; self::$locale = $locale; if (class_exists('Collator', false)) { $collator = new Collator($locale); if (!empty($collator) && $collator instanceof Collator) { // Check for non fatal error messages. This has to be done immediately // after instantiation as any further calls to collation will cause // it to reset to 0 again (or another error code if one occurred) $errorcode = $collator->getErrorCode(); $errormessage = $collator->getErrorMessage(); // Check for an error code, 0 means no error occurred if ($errorcode !== 0) { // Get the actual locale being used, e.g. en, he, zh $localeinuse = $collator->getLocale(Locale::ACTUAL_LOCALE); // Check for the common fallback warning error codes. If this occurred // there is normally little to worry about: // - U_USING_DEFAULT_WARNING (127) - default fallback locale used (pt => UCA) // - U_USING_FALLBACK_WARNING (128) - fallback locale used (de_CH => de) // (UCA: Unicode Collation Algorithm http://unicode.org/reports/tr10/) if ($errorcode === -127 || $errorcode === -128) { // Check if the locale in use is UCA default one ('root') or // if it is anything like the locale we asked for if ($localeinuse !== 'root' && strpos($locale, $localeinuse) !== 0) { // The locale we asked for is completely different to the locale // we have received, let the user know via debugging debugging('Invalid locale: "' . $locale . '", with warning (not fatal) "' . $errormessage . '", falling back to "' . $collator->getLocale(Locale::VALID_LOCALE) . '"'); } else { // Nothing to do here, this is expected! // The Moodle locale setting isn't what the collator expected but // it is smart enough to match the first characters of our locale // to find the correct locale or to use UCA collation } } else { // We've recieved some other sort of non fatal warning - let the // user know about it via debugging. debugging('Problem with locale: "' . $locale . '", with message "' . $errormessage . '", falling back to "' . $collator->getLocale(Locale::VALID_LOCALE) . '"'); } } // Store the collator object now that we can be sure it is in a workable condition self::$collator = $collator; } else { // Fatal error while trying to instantiate the collator... something went wrong debugging('Error instantiating collator for locale: "' . $locale . '", with error [' . intl_get_error_code() . '] ' . intl_get_error_message($collator)); } } } return (self::$collator instanceof Collator); }
/** * Transforms a localized date string/array into a normalized date. * * @param string|array $value Localized date string/array * * @return \DateTime Normalized date * * @throws TransformationFailedException if the given value is not a string, * if the date could not be parsed or * if the input timezone is not supported */ public function reverseTransform($value) { if (!is_string($value)) { throw new TransformationFailedException('Expected a string.'); } if ('' === $value) { return; } $timestamp = $this->getIntlDateFormatter()->parse($value); if (intl_get_error_code() != 0) { throw new TransformationFailedException(intl_get_error_message()); } try { // read timestamp into DateTime object - the formatter delivers in UTC $dateTime = new \DateTime(sprintf('@%s UTC', $timestamp)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } if ('UTC' !== $this->inputTimezone) { try { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } } return $dateTime; }
/** * Transforms a normalized date into a localized date string. * * @param \DateTime $dateTime Normalized date * * @throws TransformationFailedException If the given value is not an instance * of \DateTime or if the date could not * be transformed * * @return string|array Localized date string/array */ public function transform($dateTime) { if (null === $dateTime) { return ''; } if (!$dateTime instanceof \DateTime) { throw new TransformationFailedException('Expected a \\DateTime.'); } // convert time to UTC before passing it to the formatter $dateTime = clone $dateTime; if ('UTC' !== $this->inputTimezone) { $dateTime->setTimezone(new \DateTimeZone('UTC')); } $value = $this->getIntlDateFormatter()->format((int) $dateTime->format('U')); if (intl_get_error_code() != 0) { throw new TransformationFailedException(intl_get_error_message()); } return $value; }
/** * Formats a message via [ICU message format](http://userguide.icu-project.org/formatparse/messages) * * It uses the PHP intl extension's [MessageFormatter](http://www.php.net/manual/en/class.messageformatter.php) * and works around some issues. * If PHP intl is not installed a fallback will be used that supports a subset of the ICU message format. * * @param string $pattern The pattern string to insert parameters into. * @param array $params The array of name value pairs to insert into the format string. * @param string $language The locale to use for formatting locale-dependent parts * @return string|boolean The formatted pattern string or `FALSE` if an error occurred */ public function format($pattern, $params, $language) { $this->_errorCode = 0; $this->_errorMessage = ''; if ($params === []) { return $pattern; } if (!class_exists('MessageFormatter', false)) { return $this->fallbackFormat($pattern, $params, $language); } // replace named arguments (https://github.com/yiisoft/yii2/issues/9678) $pattern = $this->replaceNamedArguments($pattern, $params, $newParams); $params = $newParams; $formatter = new \MessageFormatter($language, $pattern); if ($formatter === null) { $this->_errorCode = intl_get_error_code(); $this->_errorMessage = "Message pattern is invalid: " . intl_get_error_message(); return false; } $result = $formatter->format($params); if ($result === false) { $this->_errorCode = $formatter->getErrorCode(); $this->_errorMessage = $formatter->getErrorMessage(); return false; } else { return $result; } }
/** * @dataProvider parseProvider */ public function testParseIntl($pattern, $value, $expected, $errorCode = 0, $errorMessage = 'U_ZERO_ERROR') { $this->skipIfIntlExtensionIsNotLoaded(); $formatter = $this->createIntlFormatter($pattern); $this->assertSame($expected, $formatter->parse($value)); $this->assertSame($errorMessage, intl_get_error_message()); $this->assertSame($errorCode, intl_get_error_code()); $this->assertSame($errorCode != 0, intl_is_failure(intl_get_error_code())); }
/** * Returns a preconfigured IntlDateFormatter instance. * * @param bool $ignoreTimezone Use UTC regardless of the configured timezone. * * @return \IntlDateFormatter * * @throws TransformationFailedException in case the date formatter can not be constructed. */ protected function getIntlDateFormatter($ignoreTimezone = false) { $dateFormat = $this->dateFormat; $timeFormat = $this->timeFormat; $timezone = $ignoreTimezone ? 'UTC' : $this->outputTimezone; $calendar = $this->calendar; $pattern = $this->pattern; $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern); // new \intlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/bug.php?id=66323 if (!$intlDateFormatter) { throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code()); } $intlDateFormatter->setLenient(false); return $intlDateFormatter; }
function ut_main() { $timezone = 'GMT-10:00'; $locale_arr = array('en_US'); $datetype_arr = array(IntlDateFormatter::FULL, IntlDateFormatter::LONG, IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, IntlDateFormatter::NONE); $res_str = ''; $time_arr = array(0, -1200000, 1200000, 2200000000.0, -2200000000.0, 90099999, 3600, -3600); $localtime_arr1 = array('tm_sec' => 24, 'tm_min' => 3, 'tm_hour' => 19, 'tm_mday' => 3, 'tm_mon' => 3, 'tm_year' => 105); $localtime_arr2 = array('tm_sec' => 21, 'tm_min' => 5, 'tm_hour' => 7, 'tm_mday' => 13, 'tm_mon' => 4, 'tm_year' => 205); $localtime_arr3 = array('tm_sec' => 11, 'tm_min' => 13, 'tm_hour' => 0, 'tm_mday' => 17, 'tm_mon' => 11, 'tm_year' => -5); $localtime_arr = array($localtime_arr1, $localtime_arr2, $localtime_arr3); $d1 = new DateTime("2010-01-01 01:02:03", new DateTimeZone("UTC")); $d2 = new DateTime("2000-12-31 03:04:05", new DateTimeZone("UTC")); $d2->setTimezone(new DateTimeZone("PDT")); $dates = array($d1, $d2, new StdClass()); //Test format with input as a timestamp : integer foreach ($time_arr as $timestamp_entry) { $res_str .= "\n------------\n"; $res_str .= "\nInput timestamp is : {$timestamp_entry}"; $res_str .= "\n------------\n"; foreach ($locale_arr as $locale_entry) { foreach ($datetype_arr as $datetype_entry) { $res_str .= "\nIntlDateFormatter locale= {$locale_entry} ,datetype = {$datetype_entry} ,timetype ={$datetype_entry} "; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); $formatted = ut_datefmt_format($fmt, $timestamp_entry); $res_str .= "\nFormatted timestamp is : {$formatted}"; } } } //Test format with input as a localtime :array foreach ($localtime_arr as $localtime_entry) { $res_str .= "\n------------\n"; $res_str .= "\nInput localtime is : "; foreach ($localtime_entry as $key => $value) { $res_str .= "{$key} : '{$value}' , "; } $res_str .= "\n------------\n"; foreach ($locale_arr as $locale_entry) { foreach ($datetype_arr as $datetype_entry) { $res_str .= "\nIntlDateFormatter locale= {$locale_entry} ,datetype = {$datetype_entry} ,timetype ={$datetype_entry} "; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); $formatted1 = ut_datefmt_format($fmt, $localtime_entry); if (intl_get_error_code() == U_ZERO_ERROR) { $res_str .= "\nFormatted localtime_array is : {$formatted1}"; } else { $res_str .= "\nError while formatting as: '" . intl_get_error_message() . "'"; } } } } foreach ($dates as $date_entry) { foreach ($locale_arr as $locale_entry) { foreach ($datetype_arr as $datetype_entry) { $res_str .= "\n------------"; $res_str .= "\nDate is: " . var_export($date_entry, true); $res_str .= "\n------------"; $fmt = ut_datefmt_create($locale_entry, $datetype_entry, $datetype_entry, $timezone, IntlDateFormatter::GREGORIAN); $formatted1 = ut_datefmt_format($fmt, $date_entry); if (intl_get_error_code() == U_ZERO_ERROR) { $res_str .= "\nFormatted DateTime is : {$formatted1}"; } else { $res_str .= "\nError while formatting as: '" . intl_get_error_message() . "'"; } } } } return $res_str; }
/** * @dataProvider parseErrorProvider */ public function testParseErrorIntl($pattern, $value) { $errorCode = StubIntl::U_PARSE_ERROR; $errorMessage = 'Date parsing failed: U_PARSE_ERROR'; $this->skipIfIntlExtensionIsNotLoaded(); $formatter = $this->createIntlFormatter($pattern); $this->assertFalse($formatter->parse($value)); $this->assertSame($errorMessage, intl_get_error_message()); $this->assertSame($errorCode, intl_get_error_code()); $this->assertTrue(intl_is_failure(intl_get_error_code())); }
<?php /* * Check getting global error code. */ // Suppress warning messages. error_reporting(E_ERROR); if (collator_get_locale() !== false) { echo "failed\n"; } else { $check_code = intl_get_error_code() != 0; echo ($check_code ? "ok" : "failed") . "\n"; }