diff --git a/includes/SubscriptionStore.php b/includes/SubscriptionStore.php index 86f007fce..19175ef7e 100644 --- a/includes/SubscriptionStore.php +++ b/includes/SubscriptionStore.php @@ -214,6 +214,13 @@ class SubscriptionStore { if ( !$user->isRegistered() || $this->userIdentityUtils->isTemp( $user ) ) { return false; } + + $section = $target->getFragment(); + // Truncate to the database field length, taking care not to mess up multibyte characters, + // appending a marker so that we can recognize this happened and display an ellipsis later. + // Using U+001F "Unit Separator" seems appropriate, and it can't occur in wikitext. + $truncSection = strlen( $section ) > 254 ? mb_strcut( $section, 0, 254 ) . "\x1f" : $section; + $dbw = $this->dbProvider->getPrimaryDatabase(); $dbw->upsert( 'discussiontools_subscription', @@ -221,7 +228,7 @@ class SubscriptionStore { 'sub_user' => $user->getId(), 'sub_namespace' => $target->getNamespace(), 'sub_title' => $target->getDBkey(), - 'sub_section' => $target->getFragment(), + 'sub_section' => $truncSection, 'sub_item' => $itemName, 'sub_state' => $state, 'sub_created' => $dbw->timestamp(), diff --git a/includes/TopicSubscriptionsPager.php b/includes/TopicSubscriptionsPager.php index 3ca767b70..932fbe6f7 100644 --- a/includes/TopicSubscriptionsPager.php +++ b/includes/TopicSubscriptionsPager.php @@ -80,12 +80,21 @@ class TopicSubscriptionsPager extends TablePager { $this->msg( 'discussiontools-topicsubscription-pager-newtopics-label' )->escaped() . ''; } else { - $titleSection = Title::makeTitleSafe( $row->sub_namespace, $row->sub_title, $row->sub_section ); - if ( !$titleSection ) { - // Handle invalid titles (T345648) - return htmlspecialchars( $row->sub_section ); + $section = $row->sub_section; + // Detect truncated section titles: either intentionally truncated by SubscriptionStore, + // or incorrect multibyte truncation of old entries (T345648). + $last = mb_substr( $section, -1 ); + if ( $last !== '' && ( $last === "\x1f" || mb_ord( $last ) === false ) ) { + $section = substr( $section, 0, -strlen( $last ) ); + // We can't link to the section correctly, since the only link we have is truncated + return htmlspecialchars( $section ) . $this->msg( 'ellipsis' )->escaped(); } - return $linkRenderer->makeLink( $titleSection, $row->sub_section ); + $titleSection = Title::makeTitleSafe( $row->sub_namespace, $row->sub_title, $section ); + if ( !$titleSection ) { + // Handle invalid titles of any other kind, just in case + return htmlspecialchars( $section ); + } + return $linkRenderer->makeLink( $titleSection, $section ); } case '_page':