Bug #74589 [Com]: __DIR__ wrong for unicode character
| From: | ganlvtech at qq dot com | Date: | Sun, 14 May 2017 20:31:51 +0000 |
| Subject: | Bug #74589 [Com]: __DIR__ wrong for unicode character | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-209116@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=74589&edit=1
ID: 74589
Comment by: ganlvtech at qq dot com
Reported by: ganlvtech at qq dot com
Summary: __DIR__ wrong for unicode character
Status: Feedback
Type: Bug
Package: *General Issues
Operating System: Windows
PHP Version: 7.1.5
Block user comment: N
Private report: N
New Comment:
Probably reason.
When php core get the filename from system, my system returns a string with cp 936. Because php5
doesn't auto convert charset, so the strlen and mb_strlen is both 22 (one chinese character is
two bytes). But php7 convert charset automatically, so strlen is 27(1 char for 3 bytes in UTF-8) and
mb_strlen is 17.
And zend_dirname function use a macro IS_SLASH_P, and the macro call a WIN32API IsDBSCLeadByte. For
cp936(GBK), the chinese character's two bytes is both larger than 0x80, IsDBSCLeadByte always
return non-zero, even when testing the second byte.
In php7, dirname(__FILE__) passed a converted, UTF-8 string to zend_dirname, so it works well. But
there might not be a automatically conversion in the zend engine when directily using __DIR__.
In php5 conversion will never automatically apply, so the two forms both don't work.
Summary:
Everything is caused by my system's returning bp936(GBK) encoded path.
This may not be a bug of php, but it should be metioned in php docs.
Thanks.
Previous Comments:
------------------------------------------------------------------------
[2017-05-14 19:33:44] ganlvtech at qq dot com
<?php
echo __FILE__, "\n";
echo strlen(__FILE__), "\n";
echo mb_strlen(__FILE__), "\n";
?>
(php 7.1, cp 936)
D:\æ°å»ºæä»¶å¤¹>php test.php
D:\æ°å»ºæä»¶å¤¹\test.php
27
17
(php 5.4, cp 936)
D:\æ°å»ºæä»¶å¤¹>php54 test.php
D:\æ°å»ºæä»¶å¤¹\test.php
22
22
------------------------------------------------------------------------
[2017-05-14 18:16:11] ganlvtech at qq dot com
I tested GBK and UTF-8 as default_charset and php 5.4, 5.6 and 7.1.
Test Report:
php: 5.4 or 5.6
default_charset: GBK or UTF-8
Results:
D:\
D:\
bool(true)
-----
php: 7.1
default_charset: GBK or UTF-8
Results:
D:\
D:\æ°å»ºæä»¶å¤¹
bool(false)
=====
CJK charchter and even \u00a1 may cause a wrong result.
Seems that, only if trailing charchter is an ASCII character, the result can be correct.
=====
Hope that the tests above can help you.
Thanks.
------------------------------------------------------------------------
[2017-05-14 17:52:27] ganlvtech at qq dot com
php.ini is php.ini-development
default_charset => UTF-8 => UTF-8
internal_encoding => no value => no value
zend.multibyte => Off => Off
PHP version: PHP 7.1.5 (cli) (built: May 9 2017 19:48:36) ( NTS MSVC14 (Visual C++ 2015) x64 )
System: Windows 10 Home (64bit). (x64 processor)
Default language: zh-CN (There is no other system language supported in my system. My system cannot
switch into English mode)
Default code page: 936(GBK)
I tried
chcp 65001 or chcp 437, it makes no changes.
=====
I have tried in Interactive shell. It seems working correctly.
D:\æ°å»ºæä»¶å¤¹>php -a
Interactive shell
php > echo __FILE__;
php shell code
php > echo __DIR__;
D:\æ°å»ºæä»¶å¤¹
=====
I have also tried php 5.4 or php 5.6 (both are use php.ini-development)
"D:\æ°å»ºæä»¶å¤¹\test.php" shows (different from php7)
D:\
D:\
bool(true)
So, i tried
Script:
<?php
echo __DIR__, "\n";
echo dirname(__FILE__), "\n";
var_dump(__DIR__ === dirname(__FILE__));
echo __FILE__, "\n";
echo str_replace('\\', '/', __FILE__), "\n";
echo dirname(str_replace('\\', '/', __FILE__)), "\n";
?>
Result: (php 5.4)
D:\
D:\
bool(true)
D:\æ°å»ºæä»¶å¤¹\test.php
D:/æ°å»ºæä»¶å¤¹/test.php
D:/æ°å»ºæä»¶å¤¹
=====
Anything works well on Ubuntu Server 16.04 (php7.0 and php5.5 were tested).
I think it may be caused by backslash.
------------------------------------------------------------------------
[2017-05-14 14:37:47] ab@php.net
Thanks for the report. Please post additionally
- default_charset INI
- internal_encoding INI
- whether zend_multibyte is used
- whether your're on a DBCS system, codepage 932, 936 or alike
I have to say, that so far i've tried the snippet on a cp 437 system with default php.ini
settings, i see it working correctly. I guess, that there can be an issue with a particular system
codepage and non UTF-8 settings in php.ini, would be nice you to do a bit more research in this
direction.
Thanks.
------------------------------------------------------------------------
[2017-05-14 07:07:24] ganlvtech at qq dot com
Description:
------------
Save the test script to "D:\æ°å»ºæä»¶å¤¹\test.php".(There must be some
unicode character in the path)
Then execute php test.php.
On Windows, shows
D:\
D:\æ°å»ºæä»¶å¤¹
bool(false)
Save to "D:\æ°å»ºæä»¶å¤¹a\test.php", then shows
D:\æ°å»ºæä»¶å¤¹a
D:\æ°å»ºæä»¶å¤¹a
bool(true)
Save to "D:\aæ°å»ºæä»¶å¤¹\test.php", then shows
D:\
D:\aæ°å»ºæä»¶å¤¹
bool(false)
Save to "D:\aæ°å»ºæä»¶å¤¹\aæ°å»ºæä»¶å¤¹\test.php",
then shows
D:\
D:\aæ°å»ºæä»¶å¤¹\aæ°å»ºæä»¶å¤¹
bool(false)
So, you may find that. If the directory's name ends with a unicode character, then __DIR__
would miss this part, until it find a dir not ends with a unicode character.
Sorry for my poor English.
Test script:
---------------
<?php
echo __DIR__, "\n";
echo dirname(__FILE__), "\n";
var_dump(__DIR__ === dirname(__FILE__));
?>
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=74589&edit=1