Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Case-insensitive substr_compare, ksort, krsort are still locale-dependent

Open Beginner friendly
#24,552 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@lazerg is already working on this.

Since Oct 22, 2026.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
73/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
c, php
Domain
backend, testing

Research direction

Start at the substr_compare() call to zend_binary_strncasecmp_l() and the case insensitive array key comparator php_array_key_compare_string_case_unstable_i() in php-src; the issue identifies both entry points and the replacement comparison functions. Check the existing tests for substr_compare(), ksort() and krsort() with SORT_STRING | SORT_FLAG_CASE, then add regression coverage for the Turkish locale. Done means those cases match the ASCII case insensitive behavior described while the existing tests pass.

Written by the indexing model from the issue text.

Description

Bug Status: Needs Triage
Description

The following code:

<?php
foreach (['C', 'tr_TR.UTF-8'] as $locale) {
    if (setlocale(LC_CTYPE, $locale) === false) {
        throw new RuntimeException("Locale unavailable: $locale");
    }

    $values = ['I', 'h'];
    sort($values, SORT_STRING | SORT_FLAG_CASE);
    $keys = ['I' => 0, 'h' => 0];
    ksort($keys, SORT_STRING | SORT_FLAG_CASE);

    echo $locale, "\n";
    echo '  stripos:        ', var_export(stripos('I', 'i'), true), "\n";
    echo '  strncasecmp:    ', strncasecmp('I', 'i', 1), "\n";
    echo '  substr_compare: ', substr_compare('I', 'i', 0, 1, true), "\n";
    echo '  sort:           ', implode(',', $values), "\n";
    echo '  ksort:          ', implode(',', array_keys($keys)), "\n";
}

Resulted in this output:

C
  stripos:        0
  strncasecmp:    0
  substr_compare: 0
  sort:           h,I
  ksort:          h,I
tr_TR.UTF-8
  stripos:        0
  strncasecmp:    0
  substr_compare: -32
  sort:           h,I
  ksort:          I,h

But I expected this output instead:

C
  stripos:        0
  strncasecmp:    0
  substr_compare: 0
  sort:           h,I
  ksort:          h,I
tr_TR.UTF-8
  stripos:        0
  strncasecmp:    0
  substr_compare: 0
  sort:           h,I
  ksort:          h,I

Reproduction link


PHP 8.2 switched strtolower(), stripos(), sort() with SORT_STRING | SORT_FLAG_CASE # and related functions to ASCII case conversion, but substr_compare() with $case_insensitive = true and ksort()/krsort() with SORT_STRING | SORT_FLAG_CASE still follow LC_CTYPE.

The output above is from PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12. PHP 8.1.34 prints the same, except that stripos() and sort() also follow the locale (false and I,h). 8.2 changed those two but not substr_compare() or ksort().

Reproducing on PHP 8.1 to 8.5 with Docker

The official php:*-cli images have no tr_TR.UTF-8 locale, so each run generates it first. With the snippet above saved as repro.php:

for v in 8.1 8.2 8.3 8.4 8.5; do
  docker run --rm -i "php:$v-cli" sh -c '
    apt-get update -qq >/dev/null &&
    apt-get install -y -qq locales >/dev/null 2>&1 &&
    localedef -i tr_TR -f UTF-8 tr_TR.UTF-8 &&
    php -v | head -n 1 &&
    php' < repro.php
done

The 8.2 UPGRADING notes say sorting with SORT_FLAG_CASE uses ASCII case conversion, and the strtolower-ascii RFC says case-insensitive substr_compare() already did.

On master, substr_compare() calls zend_binary_strncasecmp_l(), and php_array_key_compare_string_case_unstable_i(), which ksort() and krsort() use, calls zend_binary_strcasecmp_l().

Switching these two call sites to zend_binary_strncasecmp() and zend_binary_strcasecmp() would give the documented behavior.

See https://github.com/php/php-src/pull/7506.

PHP Version
PHP 8.5.12 (cli) (built: Oct 21 2026 15:53:40) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.12, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies
Operating System

Debian GNU/Linux 13 (trixie), glibc 2.41 (php:8.5-cli Docker image)

Dominant language
C
Stars
40.7k
Forks
8.3k
Avg merge
2d 15h
Merged PRs (30d)
155

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from php/php-src

All issues in php/php-src

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.