php - glob () kan ikke finde filnavne med multibyte tegn på Windows?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg skriver en filhåndtering og skal scanne biblioteker og beskæftige mig med omdøbe filer, der kan have multibytte tegn. Jeg arbejder lokalt på Windows/Apache PHP 5.3.8 med følgende filnavne i en mappe:



  • filename.jpg

  • имяфайла.jpg

  • file 件 name.jpg

  • פילענאַמע. Jpg

  • 文件 名 .jpg



Testning på en live UNIX-server vinket fint. Tester lokalt på Windows ved hjælp af glob('./path/*') returnerer kun den første, filename.jpg.


Ved hjælp af scandir() returneres det rigtige antal filer i det mindste, men jeg får navne som ?????????.jpg (Bemærk: Det er almindelige spørgsmålstegn, ikke karakteren.


Jeg skal ende med at skrive en 'søgning' funktion for at søge rekursivt gennem hele træet for filnavne, der matcher et mønster eller med en bestemt filtypenavn, og jeg antog glob() ville være det rigtige værktøj til det, snarere end scan alle filerne og udfør mønster matching og array bygning i applikationskoden. Jeg er åben for alternative forslag, hvis det er nødvendigt.


Forudsat at dette var et almindeligt problem, søgte jeg straks Google og Stack Overflow og fandt intet selv relateret. Er dette et Windows problem? PHP mangel? Hvad er løsningen: er der noget jeg kan gøre?


Addendum: Ikke sikker på, hvordan relateret dette er, men file\_exists() vender også FALSE for disse filer, passerer i den fulde absolutte sti (ved hjælp af Notepad ++, er php filen i sig UTF-8 kodning ingen BOM). Jeg er sikker på, at stien er korrekt, da nærliggende filer uden multibyte tegn vender tilbage TRUE.


REDIGER : glob() kan finde en fil med navnet filename-äöü.jpg. Tidligere i min .htaccess fil, havde jeg AddDefaultCharset utf-8, som jeg ikke overvejede før. filename-äöü.jpg udskrives som filename-���.jpg. Den eneste virkning, der fjernede den htaccess linje, syntes at have var nu, at filnavnet udskriver normalt.


Jeg har slettet filen .htaccess fuldstændigt, og dette er mit egentlige test script i dets helhed (jeg ændrede et par filnavne fra det oprindelige indlæg):


print\_r(scandir('./uploads/')); 
print\_r(glob('./uploads/*'));


Output lokalt på Windows:


Array
(
    [0] => .
    [1] => ..
    [2] => ??? ?????.jpg
    [3] => ???.jpg
    [4] => ?????????.jpg
    [5] => filename-äöü.jpg
    [6] => filename.jpg
    [7] => test?test.jpg
)
Array
(
    [0] => ./uploads/filename-äöü.jpg
    [1] => ./uploads/filename.jpg
)


Output på fjern UNIX-server:


Array
(
    [0] => .
    [1] => ..
    [2] => filename-äöü.jpg
    [3] => filename.jpg
    [4] => test이test.jpg
    [5] => имя файла.jpg
    [6] => פילענאַמע.jpg
    [7] => 文件名.jpg
)
Array
(
    [0] => ./uploads/filename-äöü.jpg
    [1] => ./uploads/filename.jpg
    [2] => ./uploads/test이test.jpg
    [3] => ./uploads/имя файла.jpg
    [4] => ./uploads/פילענאַמע.jpg
    [5] => ./uploads/文件名.jpg
)


Da dette er en anden server, uanset platformskonfigurationen kan være anderledes, så jeg er ikke sikker på hvad jeg skal tænke, og jeg kan ikke helt tappe den på Windows endnu (kan være min PHP installation, ini-indstillinger eller Apache config) . Nogle ideer?

Bedste reference


Det ser ud til, at glob () -funktionen afhænger af, hvordan din kopi af PHP blev bygget, og om det blev kompileret med en unicode-bevidst WIN32 API (jeg tror ikke, at standardbuilid er.


Jf http://www.rooftopsolutions.nl/blog/filesystem-encoding-and-php[20]


Uddrag af kommentarer til artiklen:



   Philippe Verdy 2010-09-26 8:53

  
  Udgangen fra din PHP-installation på Windows er let at forklare:
  du installerede den forkerte version af PHP, og brugte ikke en version
  kompileret til at bruge Unicode-versionen af ​​Win32 API. Af denne grund,
  de filsystemopkald, der anvendes af PHP, bruger den gamle 'ANSI' API og så
  C/C ++ biblioteker knyttet til denne version af PHP vil først forsøge at
  konvertere UTF-8-kodet PHP-streng til den lokale 'ANSI' -kodeside
  valgt i det løbende miljø (se CHCP-kommandoen før
  starter PHP fra et kommandolinjevindue)

  
  Din version af Windows er mest sandsynligt ikke ansvarlig for denne underlige
  ting. Faktisk er dette din version af PHP, som ikke er kompileret
  korrekt, og der bruger den gamle ANSI-version af Win32 API (for
  kompatibilitet med de gamle 16-bit versioner af Windows 95/98, hvis
  filsystemsupport i kernen havde faktisk ikke direkte støtte til
  Unicode, men brugt et internt konverteringslag til at konvertere Unicode til
  den lokale ANSI kode side før du bruger den faktiske ANSI version af
  API).

  
  Genompil PHP ved hjælp af kompileringsindstillingen for at bruge UNICODE-versionen af
  Win32 API (som skal være standard i dag, og alligevel altid
  standard for PHP installeret på en server, der aldrig vil være Windows
  95 eller Windows 98 ...)

  
  Derefter vil Windows kunne gemme UTF-16 kodede filnavne (inklusive
  på FAT32-volumen, selv om det på disse volumener også vil generere en
  aliased kort navn i 8.3 format ved hjælp af filsystemets standard
  codepage, noget der kan undgås i NTFS-volumener).

  
  Alt hvad du beskriver er problemer med PHP (ukorrekt porting til
  Windows eller forkert identifikation af systemversionen ved kørsel):
  læs de README filer, der kommer med PHP kilder, der forklarer
  kompilation flag. Jeg tror virkelig, at makefile på Windows burde
  være i stand til at konfigurere og autodetektere, hvis det virkelig skal bruge KUN
  ANSI-version af API'en. Hvis du kompilerer det til en server, skal du lave
  sikker på, at konfigurationsskriptet effektivt vil opdage det fulde
  understøttelse af UNICODE versionen af ​​Win32 aPI og vil bruge den når
  kompilere PHP og ved valg af runtime biblioteker til link.

  
  Jeg bruger PHP på Windows, korrekt kompileret, og jeg ved det absolut ikke
  de problemer, du nævner i din artikel.

  
  Lad os nu glemme for evigt disse ikke-UNICODE versioner af Win32
  API (som anvender inkonsekvent den lokale ANSI kodeside for
  Windows grafisk brugergrænseflade og OEM-kodeksen for filsystem-API'erne,
  de DOS/BIOS-kompatible API'er, Console API'erne): Disse ikke-Unicode
  versioner af API'er er endda meget langsommere og dyrere end
  Unicode-versioner af API'erne, fordi de faktisk oversætter
  kodesiden til Unicode, før du bruger kernen Unicode API'er (the
  Situationen på Windows NT-baserede kerner er præcis det omvendte fra
  situation på versioner af Windows baseret på en virtuel DOS extender, sådan
  som Windows 95/98/ME).

  
  Når du ikke bruger den oprindelige version af API'en, vil dit API-opkald
  passere gennem et thunking lag, der transcode strængerne mellem
  Unicode og en af ​​de arvede ANSI- eller CHCP-udvalgte OEM-kodesider, eller
  OEM kode siden antydet på filsystemet: dette kræver yderligere
  midlertidig hukommelseallokering i den ikke-native version af Win32
  API. Dette kræver yderligere tid til at konvertere ting, før du gør det
  faktiske arbejde ved at kalde den oprindelige API.

  
  Sammenfattende: PHP-binære du installerer på Windows skal være anderledes
  afhængigt af om du kompilerede det til Windows 95/98/SE (eller den gamle
  Win16s emuleringslag til Windows 3.x, som havde en meget minimal
  understøttelse af UTF-8, kun for at understøtte Unicode-undersætene af Unicode, der anvendes
  af ANSI og OEM codapges valgt, når du starter Windows fra en DOS
  extender) eller hvis den blev kompileret til enhver anden version af Windows baseret
  på NT-kernen.

  
  Det bedste bevis på, at dette er et problem med PHP og ikke Windows, er det
  dine underlige resultater vil IKKE forekomme på andre sprog som C #,
  Javascript, VB, Perl, Ruby ... PHP har en meget dårlig historie i sporing
  versioner (og for mange historiske kildekode quirks og forkert
  antagelser, der skal deaktiveres i dag, og et inkonsekvent bibliotek
  der har arvet alle de quirks oprindeligt lavet i gamle versioner af
  PHP til gamle versioner af Windows, der endnu ikke længere er officielt
  understøttet af Microsoft eller endda af PHP selv!).

  
  Med andre ord: RTM! Eller download og installer en binær version af
  PHP for Windows precompield med de rigtige indstillinger: Jeg tror virkelig
  at PHP skal distribuere Windows-binære filer, der allerede er udarbejdet af
  standard for Unicode-versionen af ​​Win32 API, og ved hjælp af
  Unicode version af C/C ++ biblioteker: internt vil PHP-koden
  konvertere dens UTF-8-strenge til UTF-16, før du kalder Win32 API, og
  tilbage fra UTF-16 til UTF-8, når der hentes Win32-resultater i stedet for
  konvertere PHP's interne UTF-8-strenge tilbage/til den lokale OEM-kodeside
  (til filsystemopkald) eller den lokale ANSI-kodeks (for alle andre
  Win32 API'er, herunder registreringsdatabasen eller processen).


Andre referencer 1


Jeg har ikke rørt PHP i 3 eller 4 år nu, men det kan måske hjælpe:



  pathinfo () er lokalt bevidst, så for at kunne analysere en sti, der indeholder multibyte tegn korrekt, skal den tilsvarende lokalitet indstilles ved hjælp af funktionen setlocale ()



Og nogle direkte links:


pathinfo - læs den anden note [21]


om setlocale [22]


(Jeg tror, ​​at dit problem kommer fra at scanne katalogerne, og ikke fra skærmkode selv eller fra overskrifterne, da Chrome eller Firefox, hvis jeg husker godt, kan håndtere Unicode-tegn.)

Andre referencer 2


PHP på Windows bruger ikke Unicode API endnu. Så du skal bruge runtime-kodningen (uanset hvad den er) for at kunne håndtere ikke-ascii-charset.

Andre referencer 3


Begyndende med PHP 7.1 lange og UTF-8 stier på Windows understøttes direkte i kernen.

Andre referencer 4


Prøv at indstille mb\_internal\_encoding () til ' UTF-8 ', før du bruger glob [23]


mb\_internal\_encoding("UTF-8");
print\_r(glob('./uploads/*'));