1--TEST--
2mb_detect_encoding()
3--EXTENSIONS--
4mbstring
5--INI--
6mbstring.language=Japanese
7--FILE--
8<?php
9// SJIS string (BASE64 encoded)
10$sjis = base64_decode('k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg==');
11// JIS string (BASE64 encoded)
12$jis = base64_decode('GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg==');
13// EUC-JP string
14$euc_jp = "\xC6\xFC\xCB\xDC\xB8\xEC\xA5\xC6\xA5\xAD\xA5\xB9\xA5\xC8\xA4\xC7\xA4\xB9\xA1\xA301234\xA3\xB5\xA3\xB6\xA3\xB7\xA3\xB8\xA3\xB9\xA1\xA3";
15// UTF-8
16$polish1 = "Zażółć gęślą jaźń.";
17$polish2 = "Wół poszedł spać bardzo wcześnie. A to zdanie bez ogonka.";
18$hungarian = "Árvíztűrő tükörfúrógép";
19
20echo "== BASIC TEST ==\n";
21
22print("SJIS: " . mb_detect_encoding($sjis, 'SJIS') . "\n");
23print("JIS: " . mb_detect_encoding($jis, 'JIS') . "\n");
24print("EUC-JP: " . mb_detect_encoding($euc_jp, 'UTF-8,EUC-JP,JIS') . "\n");
25print("EUC-JP: " . mb_detect_encoding($euc_jp, 'JIS,EUC-JP') . "\n");
26print("UTF-8: " . mb_detect_encoding($polish1, 'UTF-8,UTF-16,ISO-8859-1') . "\n");
27print("UTF-8: " . mb_detect_encoding($polish2, 'UTF-8,UTF-16,ISO-8859-1') . "\n");
28
29echo "== ARRAY ENCODING LIST ==\n";
30
31$a = ['UTF-8', 'EUC-JP', 'SJIS', 'JIS'];
32print("JIS: " . mb_detect_encoding($jis, $a) . "\n");
33print("EUC-JP: " . mb_detect_encoding($euc_jp, $a) . "\n");
34print("SJIS: " . mb_detect_encoding($sjis, $a) . "\n");
35
36$test = "CHARSET=windows-1252:Do\xeb;John";
37$encodings = [
38    'UTF-8', 'SJIS', 'GB2312',
39    'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
40    'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
41    'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
42    'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG-5',
43    'ISO-2022-KR', 'ISO-2022-JP', 'UTF-16'
44];
45echo mb_detect_encoding($test, $encodings), "\n";
46
47$test = 'N:Müller;Jörg;;;
48X-ABUID:2E4CB084-4767-4C85-BBCA-805B1DCB1C8E\:ABPerson';
49echo mb_detect_encoding($test, ['UTF-8', 'SJIS']), "\n";
50
51$test = 'BEGIN:VCARD
52VERSION:2.1
53N;ENCODING=QUOTED-PRINTABLE:Iksi=F1ski;Piotr
54FN;ENCODING=QUOTED-PRINTABLE:Piotr Iksi=F1ski
55EMAIL;PREF;INTERNET:piotr.iksinski@somedomain.com
56X-GENDER:Male
57REV:20080716T203548Z
58END:VCARD
59';
60echo mb_detect_encoding($test, ['UTF-8', 'UTF-16']), "\n";
61
62$test = 'Dušan';
63echo mb_detect_encoding($test, ['UTF-8', 'ISO-8859-1']), "\n"; // Should be UTF-8
64
65$test = 'Živko';
66echo mb_detect_encoding($test, ['UTF-8', 'ISO-8859-1']), "\n"; // Should be UTF-8
67
68// We once had a problem where all kind of strings would be detected as 'UUENCODE'
69echo mb_detect_encoding('abc', ['UUENCODE', 'UTF-8']), "\n";
70echo mb_detect_encoding('abc', ['UUENCODE', 'QPrint', 'HTML-ENTITIES', 'Base64', '7bit', '8bit', 'SJIS']), "\n";
71
72echo "== DETECT ORDER ==\n";
73
74mb_detect_order('auto');
75
76print("JIS: " . mb_detect_encoding($jis) . "\n");
77
78print("EUC-JP: " . mb_detect_encoding($euc_jp) . "\n");
79
80print("SJIS: " . mb_detect_encoding($sjis) . "\n");
81
82echo "== INVALID PARAMETER ==\n";
83
84print("INT: " . mb_detect_encoding(1234, 'EUC-JP') . "\n"); // EUC-JP
85
86print("EUC-JP: " . mb_detect_encoding('', 'EUC-JP') . "\n");  // SJIS
87
88try {
89    var_dump(mb_detect_encoding($euc_jp, 'BAD'));
90} catch (\ValueError $e) {
91    echo $e->getMessage() . \PHP_EOL;
92}
93
94echo "== TORTURE TEST ==\n";
95
96function test($strings, $encodings) {
97    foreach ($strings as $example) {
98        foreach ($encodings as $encoding) {
99            $converted = mb_convert_encoding($example, $encoding, 'UTF-8');
100            $detected = mb_detect_encoding($converted, $encodings);
101            if ($detected !== $encoding) {
102                echo "BAD! mb_detect_encoding returned $detected (should have been $encoding)\n";
103                echo "UTF-8 was: $example\n";
104                echo "$encoding bytes: ", bin2hex($converted), "\n";
105            }
106        }
107    }
108}
109
110$jpStrings = [
111    // Hat tip to Wikipedia
112    "日本で生まれ育ったほとんどの人は、日本語を母語とする[注 3]",
113    "2019年4月現在、インターネット上の言語使用者数は、英語、中国語、スペイン語、アラビア語、ポルトガル語、マレー語/インドネシア語、フランス語に次いで8番目に多い[13][信頼性要検証]。",
114    "日本語は地方ごとに多様な方言があり、とりわけ琉球諸島[要曖昧さ回避]で方言差が著しい(「方言」の節参照)。",
115    "さ  し   す   せ   そ   しゃ  しゅ  しょ  (清音)
116     た   ち   つ   て   と   ちゃ  ちゅ  ちょ  (清音)
117     な   に   ぬ   ね   の   にゃ  にゅ  にょ  ――",
118    "明治時代に入り、1889年から大槻文彦編の小型辞書『言海』が刊行された。これは、古典語・日常語を網羅し、五十音順に見出しを並べて、品詞・漢字表記・語釈を付した初の近代的な日本語辞書であった。『言海』は、後の辞書の模範的存在となり、後に増補版の『大言海』も刊行された。",
119    "奈良時代には『楊氏漢語抄』や『弁色立成(べんしきりゅうじょう)』という辞書が編纂された。それぞれ逸文として残るのみであるが、和訓を有する漢和辞書であったらしい。",
120    "複雑な文字体系を理由に、日本語を特殊とする議論もある。",
121    "一時的流行語。ある時代の若い世代が使う言葉。戦後の「アジャパー」、1970年代の「チカレタビー」など。コーホート語(同世代語)。",
122    "外国人による日本語研究も、中世末期から近世前期にかけて多く行われた。イエズス会では日本語とポルトガル語の辞書『日葡辞書』(1603年)が編纂され、また、同会のロドリゲスにより文法書『日本大文典』(1608年)および『日本小文典』(1620年)が表された。",
123    "一方、戦後になると各地の方言が失われつつあることが危惧されるようになった。NHK放送文化研究所は、(昭和20年代の時点で)各地の純粋な方言は80歳以上の老人の間でのみ使われているにすぎないとして、1953年から5年計画で全国の方言の録音を行った。",
124    "文体史 和漢混淆文の誕生",
125    "仮名遣いについては、早く小学校令施行規則(1900年)において、「にんぎやう(人形)」を「にんぎょー」とするなど、漢字音を発音通りにする、いわゆる「棒引き仮名遣い」が採用されたことがあった。",
126    "元来、日本に文字と呼べるものはなく、言葉を表記するためには中国渡来の漢字を用いた(いわゆる神代文字は後世の偽作とされている[167])。",
127    "第二次世界大戦が激しくなるにつれて、外来語を禁止または自粛する風潮も起こったが、戦後はアメリカ発の外来語が爆発的に多くなった。",
128    "そこから類推した結果、「文字を読む」に対して「文字が読むる(読める)」などの可能動詞が出来上がったものと考えられる。",
129    "近代以降には、外国語(特に英語)の音の影響で新しい音が使われ始めた。比較的一般化した「シェ・チェ・ツァ・ツェ・ツォ・ティ・ファ・フィ・フェ・フォ・ジェ・ディ・デュ」などの音に加え、場合によっては、「イェ・ウィ・ウェ・ウォ・クァ・クィ・クェ・クォ・ツィ・トゥ・グァ・ドゥ・テュ・フュ」などの音も使われる[147]。",
130    "20世紀後半から21世紀初頭にかけて中央競馬のトップジョッキーとして活躍し、競馬ファンから名手の愛称で親しまれた。",
131    "名鉄モ600形電車(めいてつモ600がたでんしゃ)は、名古屋鉄道(名鉄)が岐阜地区の直流600 V電化路線区の一つである美濃町線において運用する目的で、1970年(昭和45年)に導入した電車である。",
132    "その視点から、真理は当初未就学期の娘を幼稚園に入園させる考えは持っていなかったが、",
133    // And here's to everyone's favorite blue robot...
134    "機械だって 涙を流して 震えながら 勇気を叫ぶだろう",
135    "台風だって 心を痛めて 愛を込めて さよならするだろう",
136    "便利な道具で 助けてくれる おもちゃの 兵器だ 「ソレ!とつげき!」"
137];
138$jpEncodings = [
139    'UTF-32BE',
140    'UTF-32LE',
141    'UTF-16BE',
142    'UTF-16LE',
143    'UTF-8',
144    'UTF-7',
145    'EUC-JP',
146    'SJIS',
147    'ISO-2022-JP'
148];
149test($jpStrings, $jpEncodings);
150
151$cnStrings = [
152    "日本宫内厅宣布,真子公主和小室圭将在10月26日完婚。",
153    // The Dream of Red Mansions
154    "此开卷第一回也。作者自云曾历过一番梦幻之后,故将真事隐去,而借“通灵”说此《石头记》一书也",
155    "一日,炎夏永昼,士隐于书房闲坐,手倦抛书,伏几盹睡。",
156    "  须臾,茶毕,早已设下杯盘。",
157    "士隐听了,便迎上来道:“你满口说些什么?只听见些“好了”“好了”。",
158    "士隐送雨村去后,回房一觉,直至红日三竿方醒。",
159    "时逢三五便团圞,满把清光护玉栏。",
160    "但弟子愚拙,不能洞悉明白。",
161    "按那石头上书云:当日地陷东南,这东南有个姑苏城,城中阊门",
162    "后来既受天地精华,复得甘露滋养,遂脱了草木之胎,幻化人形,仅仅修成女体,终日游于“离恨天”外,饥餐“秘情果”,渴饮“灌愁水”。",
163    "原来雨村自那日见了甄家丫鬟,曾回顾他两次,自谓是个知己,便时刻放在心上。",
164    // Wikipedia
165    // (A lot of this uses traditional Chinese characters, which we also want to be tested)
166    "漢语主要使用漢字書寫,為語素文字。",
167    "現漢字擁有兩套文字系統,分別為正體字與簡體字。",
168    "標準漢語中四個主要的聲調,使用ma這個音節發音。",
169    "在語言學原則上,互相之間不能通話的應該被定性為語言而非方言。",
170    "但不少詞彙會採用粵語詞彙(例如採用「巴士」而非「公車」,採用「魚蛋」而非「魚丸子」,採用「沙律」而非「色拉」)",
171    "這是因為其他國家(除日本外)均使用表音文字,對於“文”[6]與“語”[7]並不作區分,不符合漢語語法",
172    "主条目:闽语、閩東語、福州語、閩南語和臺灣閩南語",
173    "普通話中,ai,ei,ao,ou等都是雙元音韻母",
174    "汉字",
175    "实词,词汇中含有实际意义的词语",
176    "我的老師 一位顧客 恭敬地鞠躬 完全相信 非常堅強 多麼可愛",
177    "敬畏生命 熱愛工作 上中學 登泰山 蓋房子 包餃子",
178    "参见:外來語 § 漢語外來語、中文外來語、汉字文化圈和汉字复活",
179    "如果将汉语延深入汉文,则汉文的信息密度更大。",
180    "我們家蓋了新房子。",
181    "他是一個高而瘦的老人。",
182    "我們家的臺階低。",
183    "我們家蓋了新房子。",
184    "敵人監視着葦塘。",
185    "連詞:用來連接詞、短語或句子,表示前後有並列、遞進、轉折、因果、假設等關係。",
186    "「大去之期不遠矣」",
187    "“官话方言”绝大多数次级方言都没有入声",
188    "其中,闽南语不仅有 −p,−t,−k,也有模糊入声"
189];
190$cnEncodings = [
191    'UTF-32BE',
192    'UTF-32LE',
193    'UTF-16BE',
194    'UTF-16LE',
195    'UTF-8',
196    'UTF-7',
197    'GB18030',
198    'BIG-5'
199];
200test($cnStrings, $cnEncodings);
201
202$deStrings = [
203    // Much love to Wikipedia
204    "Die beiden Brücken über den Strelasund (2011)",
205    "die Rügenbrücke und der Rügendamm sowie die regelmäßig betriebenen Fährverbindungen zwischen Stralsund",
206    "Der „Rügendamm“ ist die erste feste Strelasundquerung",
207    "Koordinaten    ♁54° 18′ 39″ N, 13° 7′ 0″ O",
208    "Die ausschließlich dem Kraftfahrzeugverkehr",
209    "Die Brücke ermöglicht dem Schiffsverkehr eine Durchfahrtshöhe von 40 m.[1]",
210    "Nach der Hauptbrücke folgt die Vorlandbrücke Dänholm (BW 3), eine 532,3 m",
211    "Die alte, als Klappbrücke ausgeführte Ziegelgrabenbrücke ist 133 Meter lang",
212    "Vor allem das Fährdorf Stralow („stral“ bedeutet im Mittelniederdeutschen und im Slawischen „Pfeil“) entwickelte sich rasch.",
213    "1946 kam es aufgrund der Zerstörung der Brücken",
214    "Auf der Trajektstrecke verkehrten im ersten Jahr bereits 90.000 Fahrgäste",
215    "Mai 1897 zwei Schnellzugpaare zwischen Berlin und Saßnitz.",
216    "Der Damm im Ziegelgraben und zwischen dem Dänholm und dem Widerlager der Brücke wurde mit den bei den Eisenbahnarbeiten gewonnenen Böden verfüllt.",
217    "Dabei passierten die vier anderen Trajekte die „Altefähr“",
218    "Ebenfalls in den 1980er Jahren traten zunehmend Ermüdungserscheinungen an den stark beanspruchten Stahlüberbauten auf",
219    "Erste Planungen für einen neuen Rügendamm
220Die Kapazität der Eisenbahnbrücke war begrenzt:",
221    "bestehend aus den Firmen Walter Bau AG vereinigt mit Dywidag (später/nach v.g. Insolvenz durch die Dywidag Bau GmbH)",
222    "Bereits im Herbst 1998 erfolgten die ersten Bohrungen zur Untersuchung der Tragfähigkeit des Baugrundes im Bereich des Ziegelgrabens"
223];
224$deEncodings = [
225    'UTF-32BE',
226    'UTF-32LE',
227    'UTF-16BE',
228    'UTF-16LE',
229    'UTF-8',
230    'ISO-8859-1'
231    // TODO: It would be good if ISO-8859-2 and ISO-8859-15 can be accurately detected as well
232];
233test($deStrings, $deEncodings);
234
235test([$polish1, $polish2], ['UTF-32BE', 'UTF-32LE', 'UTF-16BE', 'UTF-16LE', 'UTF-8', 'ISO-8859-2']);
236
237$czechStrings = [
238    // Gotta love these Czech proverbs
239    // "Some like girls, others like muffins." Truer words were never spoken.
240    'Bezdomovec je doma všude.',
241    'Bez práce nejsou koláče.',
242    'Bez peněz do hospody nelez.',
243    'Bližší košile nežli kabát.',
244    'Boží mlýny melou pomalu, ale jistě.',
245    'Co je dovoleno pánovi, není dovoleno kmánovi.',
246    'Co je šeptem, to je s čertem.',
247    'Co je v domě, není pro mě.',
248    'Co je v domě, to se počítá.',
249    'Co jsi z úst vypustil, ani párem koní nedostaneš zpět.',
250    'Co můžeš udělat dnes, neodkládej na zítřek.',
251    'Co nejde po dobrým, to půjde po zlým.',
252    'Co oči nevidí, to srdce nebolí (a ruce neukradnou).',
253    'Co se škádlívá, to se rádo mívá.',
254    'Co se v mládí naučíš, ke stáru jako když najdeš.',
255    'Co sis uvařil, to si sněz.',
256    'Co tě nezabije, to tě posílí.',
257    'Cvik dělá mistra.',
258    'Co tě nepálí, nehas.',
259    'Co na srdci, to na jazyku.',
260    'Co nejde silou, jde rozumem.',
261    'Čas všechny rány zahojí.',
262    'Častá krůpěj kámen proráží.',
263    'Čím výše vystoupíš, tím hlouběji padáš.',
264    'Čím výše vystoupíš, tím větší rozhled.',
265    'Čiň čertu dobře, peklem se ti odmění.',
266    'Čistota – půl zdraví.',
267    'Dal ses na vojnu, tak bojuj.',
268    'Darovanému koni na zuby nehleď.',
269    'Devatero řemesel – desátá bída.',
270    'Dějiny píší vítězové.',
271    'Dobré slovo i železná vrata otvírá.',
272    'Dočkej času jako husa klasu.',
273    'Drzé čelo lepší než poplužní dvůr.',
274    'Dvakrát měř, jednou řež.',
275    'Důvěřuj, ale prověřuj',
276    'Hlad je nejlepší kuchař.',
277    'Hlad má velké oči.',
278    'Hloupý, kdo dává, hloupější, kdo nebere.',
279    'Hněv je špatný rádce.',
280    'Někdo rád holky, jinej zas vdolky.',
281    'Volům kroky a jelenům skoky.',
282    'Vrána k vráně sedá, rovný rovného si hledá.',
283    'Všeho nechám, už tam spěchám.',
284    'Všechna sláva, polní tráva.',
285    'Všeho s mírou.',
286    'Všechno zlé je pro něco dobré.',
287    'Všude dobře, doma nejlépe.',
288    'Vrána vráně oči nevyklove.',
289    'Výjimka potvrzuje pravidlo.',
290    'Vzduch – boží duch.',
291    'Za dobrotu na žebrotu.',
292    'Zadarmo ani kuře nehrabe.',
293    'Zahálky jsa služebníkem, neběduj, žes hadrníkem.',
294    'Z cizího krev neteče.',
295    'Zítra je taky den.',
296    'Zakázané ovoce chutná nejlépe.',
297    'Zlaté slovo, které zůstane v ústech.',
298    'Zvyk je železná košile.',
299    'Žába močál vždy najde.',
300    'Žádná píseň není tak dlouhá, aby jí nebyl konec.',
301    'Žádný strom neroste do nebe.',
302    'Žádný učený z nebe nespadl.',
303    'Žízeň je věčná.'
304];
305$czechEncodings = [
306    'UTF-8',
307    'UTF-16',
308    // 'Windows-1250', // Windows-1250 is not supported by mbstring
309    // 'ISO-8859-2' // We are not able to accurately distinguish UTF-8 and ISO-8859-2
310];
311test($czechStrings, $czechEncodings);
312
313test([$hungarian], ['UTF-8', 'UTF-16', 'Windows-1252']);
314
315echo "Done!\n";
316
317?>
318--EXPECT--
319== BASIC TEST ==
320SJIS: SJIS
321JIS: JIS
322EUC-JP: EUC-JP
323EUC-JP: EUC-JP
324UTF-8: UTF-8
325UTF-8: UTF-8
326== ARRAY ENCODING LIST ==
327JIS: JIS
328EUC-JP: EUC-JP
329SJIS: SJIS
330ISO-8859-1
331UTF-8
332UTF-8
333UTF-8
334UTF-8
335UTF-8
336SJIS
337== DETECT ORDER ==
338JIS: JIS
339EUC-JP: EUC-JP
340SJIS: SJIS
341== INVALID PARAMETER ==
342INT: EUC-JP
343EUC-JP: EUC-JP
344mb_detect_encoding(): Argument #2 ($encodings) contains invalid encoding "BAD"
345== TORTURE TEST ==
346Done!
347