Skip to content

Commit ea4cee9

Browse files
Danacksmalyshev
authored andcommitted
Allow valid multi-byte utf-8 characters to be allowed as file names in phar archives.
1 parent 68283c9 commit ea4cee9

File tree

5 files changed

+165
-62
lines changed

5 files changed

+165
-62
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ PHP NEWS
1515
. Fixed bug #66908 (php-fpm reload leaks epoll_create() file descriptor).
1616
(Julio Pintos)
1717

18+
- Phar:
19+
. Fix bug #64498 ($phar->buildFromDirectory can't compress file with an accent
20+
in its name). (PR #588)
21+
1822
?? ??? 2014, PHP 5.4.28
1923

2024
- Core:

ext/phar/phar_path_check.c

+116-54
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Generated by re2c 0.13.5 on Fri Feb 25 04:35:39 2011 */
1+
/* Generated by re2c 0.13.5 on Sun Apr 20 17:14:40 2014 */
22
#line 1 "ext/phar/phar_path_check.re"
33
/*
44
+----------------------------------------------------------------------+
@@ -46,60 +46,69 @@ phar_path_check_result phar_path_check(char **s, int *len, const char **error)
4646
#line 47 "ext/phar/phar_path_check.c"
4747
{
4848
YYCTYPE yych;
49+
unsigned int yyaccept = 0;
4950

5051
if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
5152
yych = *YYCURSOR;
52-
if (yych <= '.') {
53-
if (yych <= '\n') {
54-
if (yych <= 0x00) goto yy13;
55-
if (yych <= '\t') goto yy10;
56-
goto yy12;
53+
if (yych <= '>') {
54+
if (yych <= 0x19) {
55+
if (yych <= 0x00) goto yy16;
56+
if (yych == '\n') goto yy15;
57+
goto yy14;
5758
} else {
58-
if (yych <= 0x19) goto yy10;
59-
if (yych == '*') goto yy6;
60-
goto yy15;
59+
if (yych <= '*') {
60+
if (yych <= ')') goto yy18;
61+
goto yy6;
62+
} else {
63+
if (yych != '/') goto yy18;
64+
}
6165
}
6266
} else {
63-
if (yych <= '?') {
64-
if (yych <= '/') goto yy2;
65-
if (yych <= '>') goto yy15;
66-
goto yy8;
67-
} else {
67+
if (yych <= 0x7F) {
68+
if (yych <= '?') goto yy8;
6869
if (yych == '\\') goto yy4;
69-
if (yych <= 0x7F) goto yy15;
70-
goto yy10;
70+
goto yy18;
71+
} else {
72+
if (yych <= 0xDF) {
73+
if (yych <= 0xBF) goto yy14;
74+
goto yy10;
75+
} else {
76+
if (yych <= 0xEF) goto yy12;
77+
if (yych <= 0xF7) goto yy13;
78+
goto yy14;
79+
}
7180
}
7281
}
73-
yy2:
82+
yyaccept = 0;
7483
yych = *(YYMARKER = ++YYCURSOR);
7584
if (yych <= '-') goto yy3;
76-
if (yych <= '.') goto yy16;
77-
if (yych <= '/') goto yy18;
85+
if (yych <= '.') goto yy29;
86+
if (yych <= '/') goto yy30;
7887
yy3:
79-
#line 93 "ext/phar/phar_path_check.re"
88+
#line 105 "ext/phar/phar_path_check.re"
8089
{
8190
goto loop;
8291
}
83-
#line 84 "ext/phar/phar_path_check.c"
92+
#line 93 "ext/phar/phar_path_check.c"
8493
yy4:
8594
++YYCURSOR;
86-
#line 60 "ext/phar/phar_path_check.re"
95+
#line 63 "ext/phar/phar_path_check.re"
8796
{
8897
*error = "back-slash";
8998
return pcr_err_back_slash;
9099
}
91-
#line 92 "ext/phar/phar_path_check.c"
100+
#line 101 "ext/phar/phar_path_check.c"
92101
yy6:
93102
++YYCURSOR;
94-
#line 64 "ext/phar/phar_path_check.re"
103+
#line 67 "ext/phar/phar_path_check.re"
95104
{
96105
*error = "star";
97106
return pcr_err_star;
98107
}
99-
#line 100 "ext/phar/phar_path_check.c"
108+
#line 109 "ext/phar/phar_path_check.c"
100109
yy8:
101110
++YYCURSOR;
102-
#line 68 "ext/phar/phar_path_check.re"
111+
#line 71 "ext/phar/phar_path_check.re"
103112
{
104113
if (**s == '/') {
105114
(*s)++;
@@ -108,22 +117,39 @@ phar_path_check_result phar_path_check(char **s, int *len, const char **error)
108117
*error = NULL;
109118
return pcr_use_query;
110119
}
111-
#line 112 "ext/phar/phar_path_check.c"
120+
#line 121 "ext/phar/phar_path_check.c"
112121
yy10:
113122
++YYCURSOR;
123+
if ((yych = *YYCURSOR) <= 0x7F) goto yy11;
124+
if (yych <= 0xBF) goto yy27;
114125
yy11:
115-
#line 76 "ext/phar/phar_path_check.re"
126+
#line 88 "ext/phar/phar_path_check.re"
116127
{
117128
*error ="illegal character";
118129
return pcr_err_illegal_char;
119130
}
120-
#line 121 "ext/phar/phar_path_check.c"
131+
#line 132 "ext/phar/phar_path_check.c"
121132
yy12:
122-
yych = *++YYCURSOR;
133+
yyaccept = 1;
134+
yych = *(YYMARKER = ++YYCURSOR);
135+
if (yych <= 0x7F) goto yy11;
136+
if (yych <= 0xBF) goto yy24;
123137
goto yy11;
124138
yy13:
139+
yyaccept = 1;
140+
yych = *(YYMARKER = ++YYCURSOR);
141+
if (yych <= 0x7F) goto yy11;
142+
if (yych <= 0xBF) goto yy19;
143+
goto yy11;
144+
yy14:
145+
yych = *++YYCURSOR;
146+
goto yy11;
147+
yy15:
148+
yych = *++YYCURSOR;
149+
goto yy11;
150+
yy16:
125151
++YYCURSOR;
126-
#line 80 "ext/phar/phar_path_check.re"
152+
#line 92 "ext/phar/phar_path_check.re"
127153
{
128154
if (**s == '/') {
129155
(*s)++;
@@ -137,49 +163,85 @@ phar_path_check_result phar_path_check(char **s, int *len, const char **error)
137163
*error = NULL;
138164
return pcr_is_ok;
139165
}
140-
#line 141 "ext/phar/phar_path_check.c"
141-
yy15:
166+
#line 167 "ext/phar/phar_path_check.c"
167+
yy18:
142168
yych = *++YYCURSOR;
143169
goto yy3;
144-
yy16:
170+
yy19:
145171
yych = *++YYCURSOR;
146-
if (yych <= 0x00) goto yy21;
147-
if (yych <= '-') goto yy17;
148-
if (yych <= '.') goto yy20;
149-
if (yych <= '/') goto yy21;
150-
yy17:
172+
if (yych <= 0x7F) goto yy20;
173+
if (yych <= 0xBF) goto yy21;
174+
yy20:
151175
YYCURSOR = YYMARKER;
152-
goto yy3;
153-
yy18:
176+
if (yyaccept <= 0) {
177+
goto yy3;
178+
} else {
179+
goto yy11;
180+
}
181+
yy21:
182+
yych = *++YYCURSOR;
183+
if (yych <= 0x7F) goto yy20;
184+
if (yych >= 0xC0) goto yy20;
154185
++YYCURSOR;
155-
#line 48 "ext/phar/phar_path_check.re"
186+
#line 85 "ext/phar/phar_path_check.re"
187+
{
188+
goto loop;
189+
}
190+
#line 191 "ext/phar/phar_path_check.c"
191+
yy24:
192+
yych = *++YYCURSOR;
193+
if (yych <= 0x7F) goto yy20;
194+
if (yych >= 0xC0) goto yy20;
195+
++YYCURSOR;
196+
#line 82 "ext/phar/phar_path_check.re"
197+
{
198+
goto loop;
199+
}
200+
#line 201 "ext/phar/phar_path_check.c"
201+
yy27:
202+
++YYCURSOR;
203+
#line 79 "ext/phar/phar_path_check.re"
204+
{
205+
goto loop;
206+
}
207+
#line 208 "ext/phar/phar_path_check.c"
208+
yy29:
209+
yych = *++YYCURSOR;
210+
if (yych <= 0x00) goto yy33;
211+
if (yych <= '-') goto yy20;
212+
if (yych <= '.') goto yy32;
213+
if (yych <= '/') goto yy33;
214+
goto yy20;
215+
yy30:
216+
++YYCURSOR;
217+
#line 51 "ext/phar/phar_path_check.re"
156218
{
157219
*error = "double slash";
158220
return pcr_err_double_slash;
159221
}
160-
#line 161 "ext/phar/phar_path_check.c"
161-
yy20:
222+
#line 223 "ext/phar/phar_path_check.c"
223+
yy32:
162224
yych = *++YYCURSOR;
163-
if (yych <= 0x00) goto yy23;
164-
if (yych == '/') goto yy23;
165-
goto yy17;
166-
yy21:
225+
if (yych <= 0x00) goto yy35;
226+
if (yych == '/') goto yy35;
227+
goto yy20;
228+
yy33:
167229
++YYCURSOR;
168-
#line 56 "ext/phar/phar_path_check.re"
230+
#line 59 "ext/phar/phar_path_check.re"
169231
{
170232
*error = "current directory reference";
171233
return pcr_err_curr_dir;
172234
}
173-
#line 174 "ext/phar/phar_path_check.c"
174-
yy23:
235+
#line 236 "ext/phar/phar_path_check.c"
236+
yy35:
175237
++YYCURSOR;
176-
#line 52 "ext/phar/phar_path_check.re"
238+
#line 55 "ext/phar/phar_path_check.re"
177239
{
178240
*error = "upper directory reference";
179241
return pcr_err_up_dir;
180242
}
181-
#line 182 "ext/phar/phar_path_check.c"
243+
#line 244 "ext/phar/phar_path_check.c"
182244
}
183-
#line 96 "ext/phar/phar_path_check.re"
245+
#line 108 "ext/phar/phar_path_check.re"
184246

185247
}

ext/phar/phar_path_check.re

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
+----------------------------------------------------------------------+
33
| phar php single-file executable PHP extension |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 2007-2013 The PHP Group |
5+
| Copyright (c) 2007-2014 The PHP Group |
66
+----------------------------------------------------------------------+
77
| This source file is subject to version 3.01 of the PHP license, |
88
| that is bundled with this package in the file LICENSE, and is |
@@ -42,6 +42,9 @@ phar_path_check_result phar_path_check(char **s, int *len, const char **error)
4242
loop:
4343
/*!re2c
4444
END = "\x00";
45+
MB2 = ([\xC0-\xDF][\x80-\xBF]);
46+
MB3 = ([\xE0-\xEF][\x80-\xBF]{2});
47+
MB4 = ([\xF0-\xF7][\x80-\xBF]{3});
4548
ILL = [\x01-\x19\x80-\xFF];
4649
EOS = "/" | END;
4750
ANY = .;
@@ -73,6 +76,15 @@ ANY = .;
7376
*error = NULL;
7477
return pcr_use_query;
7578
}
79+
MB2 {
80+
goto loop;
81+
}
82+
MB3 {
83+
goto loop;
84+
}
85+
MB4 {
86+
goto loop;
87+
}
7688
ILL {
7789
*error ="illegal character";
7890
return pcr_err_illegal_char;

ext/phar/tests/create_new_phar.phpt

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@ phar.require_hash=1
99
<?php
1010

1111
file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php',
12-
'brand new!');
12+
"brand new!\n");
1313
include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/a.php';
14+
15+
$fileName = "ChineseFile\xE5\x84\xB7\xE9\xBB\x91.php";
16+
file_put_contents('phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/$fileName.php',
17+
'Text in utf8 file.');
18+
include 'phar://' . dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php/$fileName.php';
1419
?>
1520

1621
===DONE===
1722
--CLEAN--
1823
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
1924
--EXPECT--
2025
brand new!
26+
Text in utf8 file.
2127
===DONE===

ext/phar/tests/create_path_error.phpt

+25-6
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,26 @@ var_dump(file_get_contents($pname . '/b.php'));
2222

2323
function error_handler($errno, $errmsg)
2424
{
25-
echo "Error: $errmsg\n";
25+
echo "Error: $errmsg";
2626
}
2727

2828
set_error_handler('error_handler');
2929

30-
$checks = array('/', '.', '../', 'a/..', 'a/', 'b//a.php');
30+
$count = 0;
31+
$checks = array(
32+
'/', '.', '../', 'a/..', 'a/', 'b//a.php',
33+
"Font\xE5\x84\xB7\xE9\xBB\x91pro.ttf", //two valid multi-byte characters
34+
"\xF0\x9F\x98\x8D.ttf", // valid 4 byte char - smiling face with heart-shaped eyes
35+
"Font\xE9\xBBpro.ttf", //Invalid multi-byte character - missing last byte
36+
"Font\xBB\x91pro.ttf", //Invalid multi-byte character - missing first byte
37+
"\xFC\x81\x81\x81\x81pro.ttf", //RFC 3629 limited char points to 0000-10FFFF aka 5 byte utf-8 not valid
38+
);
3139
foreach($checks as $check)
3240
{
41+
$count++;
42+
echo "$count:";
3343
file_put_contents($pname . '/' . $check, "error");
44+
echo "\n";
3445
}
3546

3647
$phar = new Phar($fname);
@@ -54,9 +65,17 @@ foreach($checks as $check)
5465
--EXPECTF--
5566
string(5) "query"
5667
string(5) "query"
57-
Error: file_put_contents(phar://%s//): failed to open stream: phar error: file "" in phar "%s" cannot be empty
58-
Error: file_put_contents(phar://%s/.): failed to open stream: phar error: file "" in phar "%s" cannot be empty
59-
Error: file_put_contents(phar://%s/../): failed to open stream: phar error: file "" in phar "%s" cannot be empty
60-
Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: file "" in phar "%s" cannot be empty
68+
1:Error: file_put_contents(phar://%s//): failed to open stream: phar error: file "" in phar "%s" cannot be empty
69+
2:Error: file_put_contents(phar://%s/.): failed to open stream: phar error: file "" in phar "%s" cannot be empty
70+
3:Error: file_put_contents(phar://%s/../): failed to open stream: phar error: file "" in phar "%s" cannot be empty
71+
4:Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: file "" in phar "%s" cannot be empty
72+
5:
73+
6:
74+
7:
75+
8:
76+
9:Error: file_put_contents(phar:///%s): failed to open stream: phar error: invalid path "%s" contains illegal character
77+
10:Error: file_put_contents(phar:///%s): failed to open stream: phar error: invalid path "%s" contains illegal character
78+
11:Error: file_put_contents(phar:///%s): failed to open stream: phar error: invalid path "%s" contains illegal character
6179
Exception: Entry a does not exist and cannot be created: phar error: invalid path "a" contains illegal character
6280
===DONE===
81+

0 commit comments

Comments
 (0)