php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #18556 Setting locale to 'tr_TR' lowercases class names
Submitted: 2002-07-25 02:52 UTC Modified: 2012-12-04 17:32 UTC
Votes:88
Avg. Score:4.6 ± 0.9
Reproduced:65 of 72 (90.3%)
Same Version:21 (32.3%)
Same OS:23 (35.4%)
From: spud at nothingness dot org Assigned: stas
Status: Closed Package: Scripting Engine problem
PHP Version: 5CVS, 4CVS (2005-10-04) OS: Linux (RedHat 7.2)
Private report: No CVE-ID:
 [2002-07-25 02:52 UTC] spud at nothingness dot org
This bug is related to others submitted that refer to _constants_ being affected by the locale change, but since this actually concerns a class name, I wanted to submit it separately. Pardon the error if it turns out to be one...

I'm internationalizing an app, which loads (include_once) a file called 'imc_Info.inc' containing two class definitions with their respective constructors:
class Info
and
class InfoOracle

In the course of loading the index page, I call
new InfoOracle()
and perform a query. This works fine in English, Spanish, French, and Greek. If I switch my app's locale to Turkish ('tr_TR'), however, I get a error:
Cannot instantiate non-existent class:  ?acle in /var/www/html
(Yes, that ? appears in my logs). After searching for bug reports concerning Turkish, I noticed some closed/bogus reports that mentioned _case_, so I did some poking around.

Although my class constructor clearly reads
function InfoOracle() {
	blah blah blah
}
PHP fails to acknowledge it. The get_declared_classes() function DOES return "info" and "infooracle" in its array though. 

So I tried changing my call to
new infooracle(), simply lowercasing the whole name. That worked like a charm, in Turkish. I noticed in one of the other bug reports that Turkish contains no "I" in its character set, which _sort of_ explains the problem, but it still strikes me as a bug. Shouldn't class names remain unaffected by the current locale?

The following script demonstrates the problem. It generates the first output, then throws an error attempting the second.

---- SCRIPT ----
<?
// Set language to desired language 
$g_lang = 'tr_TR';
putenv("LANG=$g_lang"); 
setlocale(LC_ALL, $g_lang);

class InfoBlob {
   var $foo;
   function InfoBlob() {
      $this->foo = "Foo";
   }
}

echo ('Instantiating an infoBlob with a lowercase i<br>');
$foobar = new infoBlob();
echo ($foobar->foo);
echo ('<br>Instantiating an InfoBlob with an uppercase I<br>');
$foobar = new InfoBlob();
echo ($foobar->foo);
?>

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-07-25 03:57 UTC] hholzgra@php.net
known problem, see regression test case tests/lang/035.phpt
 [2002-07-25 04:38 UTC] sniper@php.net
dup of #16865
 [2002-08-28 21:12 UTC] sniper@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php4-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-latest.zip

Something related to this was fixed in CVS. (the #16865 which this one was marked duplicate of is closed)
 [2002-09-23 07:31 UTC] sniper@php.net

 [2002-09-26 13:56 UTC] andrei@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.


 [2006-02-17 11:49 UTC] hholzgra@php.net
This bug has resurfaced in the 5.x branches since revision 1.151 of Zend/zend_operators.h
 [2006-04-10 11:04 UTC] sniper@php.net
Andrei, care to take a look?
 [2006-08-26 15:05 UTC] bjori@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5.2-win32-latest.zip

Can't reproduce...
 [2006-09-03 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2007-06-03 22:22 UTC] mike dot ditum at tripleplay-services dot com
I can confirm that this bug is still there... I'm testing with snapshot php5.2-200706031230 and get the following...

Instantiating an infoBlob with a lowercase i<br>Foo<br>Instantiating an InfoBlob with an uppercase I<br>
Fatal error: Class 'InfoBlob' not found in /root/php5.2-200706031230/test.php on line 18

Another simple script I have discovered that shows the same problem is...

<?php
        echo setlocale(LC_ALL, "tr_TR.utf8")."\n";
        foreach(get_declared_classes() as $class)
        {
                if(!class_exists($class))
                        echo "$class No Longer Exists!\n";
        }
?>

For this program I get the following output...

[root@BlankFedora php5.2-200706031230]# sapi/cli/php  ~/test2.php
tr_TR.utf8
DOMImplementationList No Longer Exists!
DOMImplementationSource No Longer Exists!
DOMImplementation No Longer Exists!
DOMProcessingInstruction No Longer Exists!
RecursiveIteratorIterator No Longer Exists!
IteratorIterator No Longer Exists!
FilterIterator No Longer Exists!
RecursiveFilterIterator No Longer Exists!
ParentIterator No Longer Exists!
LimitIterator No Longer Exists!
CachingIterator No Longer Exists!
RecursiveCachingIterator No Longer Exists!
NoRewindIterator No Longer Exists!
AppendIterator No Longer Exists!
InfiniteIterator No Longer Exists!
RegexIterator No Longer Exists!
RecursiveRegexIterator No Longer Exists!
EmptyIterator No Longer Exists!
ArrayIterator No Longer Exists!
RecursiveArrayIterator No Longer Exists!
SplFileInfo No Longer Exists!
DirectoryIterator No Longer Exists!
RecursiveDirectoryIterator No Longer Exists!
SimpleXMLIterator No Longer Exists!
InvalidArgumentException No Longer Exists!
__PHP_Incomplete_Class No Longer Exists!

This does not just occur with tr_TR.utf8 it also occurs with the following locales... tr_CY.utf8, ku_TR.utf8 and az_AZ.utf8.

Thanks
 [2007-08-16 17:24 UTC] tokul at users dot sourceforge dot net
class_exists() function uses zend_str_tolower(). zend_str_tolower() uses
zend_tolower(). zend_tolower() uses _tolower_l() on Windows and tolower() on other oses. _tolower_l() is not locale aware. tolower() is LC_CTYPE aware.

Turkish language can trigger some i18n programming errors in case insensitive comparison functions, because small latin i is not equal to capital latin i in Turkish language. Azerbaijani (az) and Kurdish (ku) locales use Turkish language rules on Linux.

P.S. According to msdn documentation _tolower_l() is not meant to be called directly and is provided for internal use by _totlower_l
 [2008-04-21 18:40 UTC] jreeve at pelagodesign dot com
We are still getting this bug with PHP 5.2.3
PHP 5.2.3 (cli) (built: Feb  7 2008 06:40:06)

As noted below, this function:
<?php
        echo setlocale(LC_ALL, "tr_TR.utf8")."\n";
        foreach(get_declared_classes() as $class)
        {
                if(!class_exists($class))
                        echo "$class No Longer Exists!\n";
        }
?>

Produces this error:
tr_TR.utf8
DOMImplementationList No Longer Exists!
DOMImplementationSource No Longer Exists!
DOMImplementation No Longer Exists!
DOMProcessingInstruction No Longer Exists!
RecursiveIteratorIterator No Longer Exists!
IteratorIterator No Longer Exists!
FilterIterator No Longer Exists!
RecursiveFilterIterator No Longer Exists!
ParentIterator No Longer Exists!
LimitIterator No Longer Exists!
CachingIterator No Longer Exists!
RecursiveCachingIterator No Longer Exists!
NoRewindIterator No Longer Exists!
AppendIterator No Longer Exists!
InfiniteIterator No Longer Exists!
RegexIterator No Longer Exists!
RecursiveRegexIterator No Longer Exists!
EmptyIterator No Longer Exists!
ArrayIterator No Longer Exists!
RecursiveArrayIterator No Longer Exists!
SplFileInfo No Longer Exists!
DirectoryIterator No Longer Exists!
RecursiveDirectoryIterator No Longer Exists!
SimpleXMLIterator No Longer Exists!
InvalidArgumentException No Longer Exists!
__PHP_Incomplete_Class No Longer Exists!
 [2008-05-20 07:44 UTC] c dot muench at netz98 dot de
This bug is still alive in version 5.2.5.
I tested the posted script and get the same results.
 [2009-03-05 19:28 UTC] cankoy at ymail dot com
This also occurs in function names:
<?php
echo setlocale(LC_ALL, 'tr_TR')."\n";
HI5();
function HI5() { echo "Five!\n";}
?>

outputs:
---
tr_TR

Fatal error: Call to undefined function HI5() in...
---
whereas the following works OK:
<?php
echo setlocale(LC_ALL, 'tr_TR')."\n";
function HI5() { echo "Five!\n";}
HI5();
?>

outputs:
---
tr_TR
Five!
---

using php-cli 5.2.6 on Ubuntu 8.10.
 [2009-06-18 09:51 UTC] spam at pamignot dot org
This bug is still alive !!
Can someone have a look to this ?

While it is not fixed, you can set LC_CTYPE to another locale to get it works again.
 [2009-07-30 17:21 UTC] onur dot oguzel at gmail dot com
i guess nobody looks at this bug, 
setlocale(LC_ALL, 'tr_TR');
setlocale(LC_CTYPE, 'en_US');

sure solves this but it is still a bug :)
 [2009-08-04 11:23 UTC] cankoy at ymail dot com
Setting LC_CTYPE to something other than tr_TR solves nothing, it's not even a workaround, you just get a bastardized locale in which regex patterns do not match Turkish char.s and XXlower/XXupper functions become nothing but a joke.
This bug has been around for ages, so it's not fixable? OK, don't fix it, but at least provide a means to turn off(*) the horrible PHP design decision "case-insensitive function lookup", so that we have an option to avoid all this mess.

(*)like, a Php.ini directive
 [2009-11-13 16:58 UTC] joesiegrist at gmail dot com
It is unbelievable that this bug persists into 2009.  It is time to fix 
it.
 [2010-01-22 09:00 UTC] pajoye@php.net
Dmitry, can you look at it please? It is still reproduceable with 5.2 and 5.3.
 [2010-02-02 21:31 UTC] housecafe at freenet dot de

 [2010-06-13 19:11 UTC] ceremcem at cshus dot org
This bug still exists in PHP version 5.3.2.
 [2010-06-13 20:07 UTC] ceremcem at cshus dot org
EDIT: The code that I used to regenerate this bug as follows: 

foreach(get_declared_classes() as $class)
{
     if(!class_exists($class))
     echo "$class No Longer Exists!\n";
}

This code does not produce errors anymore but method names are still giving this type of error. 

I'm using ImageMagick and its PHP extension, imagick, which gives the error "fatal: thumbnailImage() method not found", seems to be related with this bug. When I rewrite the method name as ...->thumbnailimage(), all works OK. 

So, the methods documented in http://www.php.net/manual/en/class.imagick.php which include "I" (capital i), it can not be used without replacing "I" with "i". (same errors occur with MagickWand class)

Could you please fix this too?
 [2010-08-09 07:55 UTC] stevemw at mac dot com
+1.  I get complaints about the side-effects of this on a weekly basis.  
Especially awful if you are asked to add turkish support after the fact, when you 
already have a large codebase.
 [2010-08-27 19:17 UTC] web-coder at list dot ru
Please tell me php version, where this problem is already solved. Thanks.
 [2010-08-28 12:14 UTC] web-coder at list dot ru
Thanks to Alexey dot Rybak at gmail dot com for a patch, 
that fix problem if you use only ASCII-symbols in functions/methods names:
http://dev.badoo.com/custom_strtolower.diff
 [2011-08-08 12:02 UTC] tolga at profelis dot com dot tr
php -v
PHP 5.3.3-7+squeeze3 with Suhosin-Patch (cli) (built: Jun 28 2011 08:24:40)

Problem continues!
 [2011-09-15 19:51 UTC] robin dot bussiek at googlemail dot com
I am sorry to ask this for my understanding:

Is it true, that the cause for this bug lies in a false inclusion of the "I" character in the Turkish character set - and therefore results in an unnecessary replacement? 

If so, my green knowledge leads me to the assumption, that a fix should be rather simple. 

**duck**,
Robin
 [2011-09-15 19:59 UTC] sweiss at stylesight dot com
No, the problem results because lowercase i (in most languages) and uppercase I 
(in most languages) are not actually considered to be the upper/lower variant of 
the same letter in Turkish.  In Turkish, the undotted ı is the lowercase of I, 
and the dotted İ is the uppercase of i.  If you have a class named Image, it 
will break if the locale is changed to turkish because class_exists() function 
uses zend_str_tolower(), and changes the case on all classes, because they are 
supposed to be case insensitive.  Someone else above explained it very well:


class_exists() function uses zend_str_tolower(). zend_str_tolower() uses
zend_tolower(). zend_tolower() uses _tolower_l() on Windows and tolower() on 
other oses. _tolower_l() is not locale aware. tolower() is LC_CTYPE aware.

Please, oh please, can someone fix this already?  It has been a very long time 
and it's extremely annoying and difficult to work around if you have a large 
multilingual website.
 [2011-09-16 14:18 UTC] robin dot bussiek at googlemail dot com
@sweiss-at-stylesight thanks for your explanation.

Big +1 for any solution to this topic.
 [2011-11-06 19:29 UTC] gerd dot katzenbeisser at gmail dot com
here is a simple test case using the internal class PharFileInfo

<?
$class = 'PharFileInfo';
echo 'Locale: '.setlocale(LC_ALL, '0')."\n";
echo "$class exists? ".var_export(class_exists($class), true)."\n";
echo 'Locale: '.setlocale(LC_ALL, 'tr_TR.UTF-8')."\n";
echo "$class exists? ".var_export(class_exists($class), true);
?>

Output:
Locale: C
PharFileInfo exists? true
Locale: tr_TR.UTF-8
PharFileInfo exists? false
 [2011-12-03 22:08 UTC] sg at facelift-bbt dot com
This bug was first reported 9 years ago? This definetly got to be fixed. This is a total stopper. I can reproduce it exactly it is shown below.
 [2011-12-07 18:01 UTC] cankoy at ymail dot com
This, practically, can't be fixed. Mainly because there's no way to know if 'I' is uppercase of 'i' or 'ı' since there's not a separate place for Turkish 'I' in code tables. The same holds for 'i' (can't be known if it's lowercase of 'I' or 'İ').
I told 2 years ago and will say it again: PHP should provide a way to turn off case-insensitive function/class name lookup. No good programmer uses this Basic language feature since identifiers are case-sensitive in all real languages like Python, Ruby, C#, Java.
 [2011-12-07 20:01 UTC] gerd dot katzenbeisser at gmail dot com
This will probably break a lot of existing PHP Code. Why not performing the lookup 
case-sensitive and if not found fall back to case-insensitive? And if found case-
insensitive throw a deprecation warning.
 [2011-12-07 20:13 UTC] cankoy at ymail dot com
> This will probably break a lot of existing PHP Code.
Existing code is already broken for those suffering from this problem, don't you get it? 
I'm not suggesting a permanent turn-off, I'm suggesting a command-line option/a php.ini directive/whatever fits the design of Php engine to implement this as an option.

> Why not performing the lookup case-sensitive and if not found fall back to case-insensitive? And if found case-insensitive throw a deprecation warning.
You're suggesting more ceremony, where I suggest optionally skipping a ceremony. Php is an interpreter, performance is important.
 [2012-05-04 19:10 UTC] wim at powerassist dot nl
Why is this bug still not fixed? Not only class names are affected but function names aswell:

<?php
setlocale(LC_ALL, 'tr_TR.UTF-8');

class InfoBlob {
	
	public static function Intresting() {
		return 'is it not?';
	}
}

echo (infoBlob::intresting()); // works lowercase i function and class.
echo (infoBlob::Intresting()); // fails uppercase i function
echo (InfoBlob::intresting()); // fails uppercase i class 
?>
 [2012-05-05 15:33 UTC] wim at powerassist dot nl
Sorry, I was to quick to comment. I see that there's an internal mailing going on.
 [2012-05-15 20:54 UTC] inet dot alper at gmail dot com
https://github.com/php/php-src/pull/79
this patch does not break other locales, check it out.
 [2012-07-02 11:42 UTC] bobx at bob dot com
hahaha yeah PHP is garbage
 [2012-07-03 09:02 UTC] shevegen at gmail dot com
There are other languages one could use, other than PHP.
 [2012-07-03 09:58 UTC] maarten@php.net
Appears to be fixed since >= 5.4.0
See http://3v4l.org/lahi5 for proof:
---
Output for 5.4.0 - 5.4.4
    Instantiating an infoBlob with a lowercase i<br>Foo<br>Instantiating an InfoBlob with an uppercase I<br>Foo

Output for 5.0.0 - 5.0.5, 5.1.0 - 5.1.6, 5.2.0 - 5.2.17, 5.3.0 - 5.3.14
    Instantiating an infoBlob with a lowercase i<br>Foo<br>Instantiating an InfoBlob with an uppercase I<br> Fatal error: Class 'InfoBlob' not found in /in/lahi5 on line 25
    Process exited with code 255.
---
 Can't find it in the changelogs though.
 [2012-07-03 16:42 UTC] stormbyte at gmail dot com
It is not fixed in 5.4.4 as some stated above.
Tested with php 5.4.4
Testcase:
<?php
echo 'Starting...<br />';
$class = 'PharFileInfo';
echo 'Locale: '.setlocale(LC_ALL, '0')."<br />";
echo "$class exists? ".var_export(class_exists($class), true)."<br />";
echo 'Locale: '.setlocale(LC_ALL, 'tr_TR.UTF-8')."<br />";
echo "$class exists? ".var_export(class_exists($class), true)."<br />";
>?

Output with nginx+spawnFCGI:
Starting...
Locale: C
PharFileInfo exists? true
Locale: tr_TR.UTF-8
PharFileInfo exists? false

Output with cli (php -f test.php):
Starting...<br />Locale: C<br />PharFileInfo exists? true<br />Locale: tr_TR.UTF-8<br />PharFileInfo exists? false<br />
 [2012-07-03 16:53 UTC] stormbyte at gmail dot com
maarten@php.net:
They don't seem to be running vanilla PHP installations.
I've compiled php-5.4.4 from Gentoo and do not appear to be fixed to me, even in 5.4.4.

Can you try on a vanilla PHP?
 [2012-07-03 17:05 UTC] stormbyte at gmail dot com
The problem:
<?php
setlocale(LC_ALL, 'tr_TR.UTF-8');
echo strtolower('THIS IS JUST A TEST');
?>
output:
thIs Is just a test

So if it is using the same function internally to do the tolower on class names, it will not find them.

A workarround would be use toupper instead of tolower in zend_internal namespace handling, despite the correct fix would be to use independent identifyers (??)
 [2012-07-04 08:52 UTC] maarten@php.net
@ stormbyte, I just made 2 separate more explicit tests, one for tr_TR.iso8859-9 and one for tr_TR.UTF-8 and they do have the same outcome:

tr_TR.iso8859-9 - http://3v4l.org/o5YCk
tr_TR.UTF-8 - http://3v4l.org/F2gEb

3v4l.org uses a 'vanilla' PHP setup, be free to play with phpinfo() and the likes to see for yourself.
 [2012-07-14 22:59 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2012-07-14 22:59 UTC] stas@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.

Fixed in master.
 [2012-07-15 05:02 UTC] stas@php.net
-Assigned To: dmitry +Assigned To: stas
 [2012-07-16 14:21 UTC] me at ollieread dot com
I don't know how helpful this will be, but I've recently had an issue with the 
Turkish locale where I work.

I tried lots of different methods, but the main issue seems to be with LC_CTYPE, 
as although class/method declarations include I, it's added to the stack as i.

I've wrote a couple of fixes that hopefully approach all cases, be warned, they 
are however a bit hacky.

http://codeosaur.us/2012/07/16/php-and-the-tr_tr-utf8-locale/

You can simple explicitly set LC_CTYPE to your native language(eg en_US.utf8), 
but if you absolutely must have tr_TR.utf8 there, then you can use the magic of 
__autoload(), __call() and class_alias to handle it for you.

Hope this helps.
 [2012-09-08 14:25 UTC] richlv at nakts dot net
which version is expected to have the fix ? looking at snapshots, is it trunk only (thus php 5.5 or whichever will be the next version) ?

interesting bit - this bug was fixed just 9 days short of it's 10th birthday ;)
(submitted 2002-07-25, fixed 2012-07-16)
 [2012-09-08 14:54 UTC] richlv at nakts dot net
hmm, i just tested trunk snapshot php-trunk-201209081330 which announces itself as 5.4.8-dev

trying to use turkish locale still fails with :
Fatal error: Class 'CInput' not found

(there's uppercase I in the name)

what am i doing wrong ?
 [2012-09-10 06:22 UTC] stas@php.net
You should be using 5.5 (or master) branch of PHP. It is not fixed in 5.4 due to necessities of binary APIs change which is not possible in stable version. Trunk does not announce itself as 5.4 but as 5.5, so there must be some mistake. 

However if you feel very adventurous, you can take 5.5 commit (it's marked with the bug #) and cherry-pick it into your 5.4 branch.
 [2012-09-13 15:31 UTC] richlv at nakts dot net
thanks for the response.

$ wget http://snaps.php.net/php-trunk-201209131330.tar.gz
$ wget http://snaps.php.net/php-trunk-201209131330.tar.bz2
$ wget http://snaps.php.net/php-trunk-201209131330.tar.xz

$ for type in gz bz2 xz; do mkdir $type; (cd $type; tar -xf ../php-trunk-201209131330.tar.$type); done

$ grep "PHP_VERSION " {bz2,gz,xz}/php-trunk-201209131330/main/php_version.h
bz2/php-trunk-201209131330/main/php_version.h:#define PHP_VERSION "5.4.8-dev"
gz/php-trunk-201209131330/main/php_version.h:#define PHP_VERSION "5.4.8-dev"
xz/php-trunk-201209131330/main/php_version.h:#define PHP_VERSION "5.4.8-dev"

is that ok for trunk snapshots then ?
 [2012-09-13 19:19 UTC] stas@php.net
It looks like snaps is serving 5.4 under the name of php-trunk. Not sure why. 
Could you submid a website bug for that and send me the bug ID?
In the meantime you could use github: https://github.com/php/php-src just use the 
"zip file" option and you could build it from there.
 [2012-12-04 17:32 UTC] jpauli@php.net
So, to sum things up :
The bugs has only been fixed in 5.5 branch. It mainly uses a char map to lower 
characters instead of relying on locale-aware (possibly buggy versions) system's 
libc.

You can find details with internal zend functions affected directly by reading 
the source, here : http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_operators.c#45
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sat Apr 19 19:02:15 2014 UTC