print - php transform to utf8
glob() no puede encontrar nombres de archivos con caracteres multibyte en Windows? (5)
Comenzando con PHP 7.1 largo y las rutas UTF-8 en Windows son compatibles directamente en el núcleo.
Estoy escribiendo un administrador de archivos y necesito escanear directorios y lidiar con el cambio de nombre de los archivos que pueden tener caracteres multibyte. Estoy trabajando localmente en Windows / Apache PHP 5.3.8, con los siguientes nombres de archivo en un directorio:
- nombre de archivo.jpg
- имяфайла.jpg
- archivo 件 nombre.jpg
- פילענאַמע. Jpg
- 文件 名 .jpg
Las pruebas en un servidor de UNIX activo funcionó bien. Probar localmente en Windows usando glob(''./path/*'')
devuelve solo el primero, filename.jpg
.
Usando scandir()
, al menos se devuelve la cantidad correcta de archivos, pero obtengo nombres como ?????????.jpg
(nota: esos son signos de interrogación regulares, no el carácter .
Terminaré necesitando escribir una función de "búsqueda" para buscar recursivamente en todo el árbol nombres de archivos que coincidan con un patrón o con cierta extensión de archivo, y asumí que glob()
sería la herramienta adecuada para eso, en lugar de escanear todo Los archivos y hacer la coincidencia de patrones y la formación de matriz en el código de la aplicación. Estoy abierto a sugerencias alternativas si es necesario.
Asumiendo que esto era un problema común, inmediatamente busqué Google y Stack Overflow y no encontré nada relacionado. ¿Es este un problema de Windows? ¿Deficiencia de PHP? ¿Cuál es la solución? ¿Hay algo que pueda hacer?
Adición: No estoy seguro de qué tan relacionado está esto, pero file_exists()
también devuelve FALSE
para estos archivos, pasando por la ruta absoluta completa (usando Notepad ++, el archivo php en sí es codificación UTF-8 sin lista de materiales). Estoy seguro de que la ruta es correcta, ya que los archivos vecinos sin caracteres multibyte devuelven TRUE
.
EDIT : glob()
puede encontrar un archivo llamado filename-äöü.jpg
. Anteriormente en mi archivo .htaccess
, tenía AddDefaultCharset utf-8
, que no había considerado antes. filename-äöü.jpg
estaba imprimiendo como filename- .jpg
. El único efecto que parecía tener esa línea htaccess ahora era que el nombre del archivo se imprime normalmente.
He eliminado el archivo .htaccess
completamente, y este es mi script de prueba real en su totalidad (cambié un par de nombres de archivo de la publicación original):
print_r(scandir(''./uploads/''));
print_r(glob(''./uploads/*''));
Salida localmente en 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
)
Salida en servidor remoto UNIX:
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
)
Como este es un servidor diferente, independientemente de la plataforma, la configuración podría ser diferente, así que no estoy seguro de qué pensar, y aún no puedo identificarlo completamente en Windows (podría ser mi instalación de PHP, configuración ini o configuración de Apache) . ¿Algunas ideas?
Intente configurar mb_internal_encoding() en " UTF-8 " antes de usar glob
mb_internal_encoding("UTF-8");
print_r(glob(''./uploads/*''));
No he tocado PHP desde hace 3 o 4 años, pero tal vez esto ayude:
pathinfo () es consciente de la configuración regional, por lo que para analizar correctamente una ruta que contenga caracteres multibyte, la configuración regional correspondiente debe configurarse mediante la función setlocale ()
Y algunos enlaces directos:
pathinfo - lee la segunda nota
(Creo que su problema proviene del escaneo de los directorios, y no del código de visualización en sí mismo o de los encabezados, ya que Chrome o Firefox, si mal no recuerdo, pueden manejar caracteres Unicode).
PHP en Windows aún no usa la API Unicode. Así que tienes que usar la codificación de tiempo de ejecución (sea lo que sea) para poder lidiar con el conjunto de caracteres no ascii.
Parece que la función glob () depende de cómo se compiló su copia de PHP y de si se compiló con una API WIN32 compatible con unicode (no creo que sea el builid estándar).
Cf. http://www.rooftopsolutions.nl/blog/filesystem-encoding-and-php
Extracto de los comentarios sobre el artículo:
Philippe Verdy 2010-09-26 8:53 am
El resultado de su instalación de PHP en Windows es fácil de explicar: instaló la versión incorrecta de PHP y utilizó una versión no compilada para usar la versión Unicode de la API de Win32. Por esta razón, las llamadas al sistema de archivos usadas por PHP usarán la API heredada "ANSI" y las bibliotecas C / C ++ vinculadas con esta versión de PHP intentarán primero convertir su cadena PHP codificada en UTF-8 en el "ANSI" local. página de códigos seleccionada en el entorno en ejecución (consulte el comando CHCP antes de iniciar PHP desde una ventana de línea de comandos)
Tu versión de Windows NO ES PROBABLEMENTE RESPONSABLE de esta cosa extraña. En realidad, esta es SU versión de PHP que no está compilada correctamente y usa la versión ANSI heredada de la API de Win32 (por compatibilidad con las versiones heredadas de 16 bits de Windows 95/98 cuyo soporte del sistema de archivos en el kernel en realidad no tenía directivas soporte para Unicode, pero usó una capa de conversión interna para convertir Unicode a la página de códigos ANSI local antes de usar la versión ANSI real de la API).
Recompile PHP utilizando la opción del compilador para usar la versión UNICODE de la API de Win32 (que debería ser la predeterminada de hoy, y de todos modos siempre la predeterminada para PHP instalado en un servidor que NUNCA será Windows 95 o Windows 98 ...)
Entonces Windows podrá almacenar nombres de archivos codificados en UTF-16 (incluso en volúmenes FAT32, incluso si, en estos volúmenes, también generará un nombre corto alias en formato 8.3 utilizando la página de códigos predeterminada del sistema de archivos, algo que se puede evitar en volúmenes NTFS )
Todo lo que describe son problemas de PHP (conversión incorrecta a Windows o identificación incorrecta de la versión del sistema en tiempo de ejecución): vuelva a leer los archivos README que vienen con las fuentes de PHP que explican los indicadores de compilación. Realmente creo que el makefile en Windows debería poder configurarse y autodetectarse si realmente necesita usar SOLO la versión ANSI de la API. Si está compilando para un servidor, asegúrese de que la secuencia de comandos Configure detectará efectivamente la compatibilidad total de la versión UNICODE del API de Win32 y la usará al compilar PHP y al seleccionar las bibliotecas de tiempo de ejecución para vincular.
Utilizo PHP en Windows, compilado correctamente, y NO SÍ conozco los problemas que citan en su artículo.
Olvidemos ahora para siempre estas versiones no UNICODE de la API de Win32 (que usan inconsistentemente la página de códigos ANSI local para la interfaz gráfica de usuario de Windows y la página de códigos OEM para las API de sistema de archivos, las API compatibles con DOS / BIOS, las API de consola): estas versiones de las API que no son Unicode son MUCHO más lentas y costosas que las versiones Unicode de las API, porque en realidad están traduciendo la página de códigos a Unicode antes de usar las API Unicode principales (la situación en kernels basados en Windows NT es exactamente la revierta de la situación en versiones de Windows basadas en un extensor de DOS virtual, como Windows 95/98 / ME).
Cuando no utiliza la versión nativa de la API, su llamada a la API pasará por una capa de transferencia que transcodificará las cadenas entre Unicode y una de las páginas de códigos OEM seleccionadas por ANSI o CHCP, o la página de códigos OEM insinuada en el sistema de archivos. : esto requiere una asignación de memoria temporal adicional dentro de la versión no nativa de la API de Win32. Esto toma tiempo adicional para convertir las cosas antes de hacer el trabajo real llamando a la API nativa.
En resumen: el binario de PHP que instale en Windows DEBE ser diferente dependiendo de si lo compiló para Windows 95/98 / SE (o la antigua capa de emulación Win16s para Windows 3.x, que tenía un soporte muy mínimo de UTF-8, solo para admitir los subconjuntos Unicode de Unicode utilizados por los codapges ANSI y OEM seleccionados al iniciar Windows desde un extensor de DOS) o si se compiló para cualquier otra versión de Windows basada en el kernel de NT.
La mejor prueba de que este es un problema de PHP y no de Windows, es que sus resultados extraños NO ocurrirán en otros lenguajes como C #, Javascript, VB, Perl, Ruby ... PHP tiene un historial muy malo en el seguimiento de versiones (y también muchas peculiaridades históricas del código fuente y suposiciones erróneas que deberían deshabilitarse hoy, y una biblioteca inconsistente que ha heredado todas esas peculiaridades hechas inicialmente en versiones anteriores de PHP para versiones anteriores de Windows que ni siquiera son oficialmente soportadas por Microsoft o incluso por PHP sí mismo !).
En otras palabras: ¡RTM! O descargue e instale una versión binaria de precompield de PHP para Windows con la configuración correcta: realmente creo que PHP debería distribuir los binarios de Windows ya compilados de forma predeterminada para la versión Unicode de la API de Win32 y utilizando la versión Unicode de las bibliotecas C / C ++ : internamente, el código PHP convertirá sus cadenas UTF-8 a UTF-16 antes de llamar a la API Win32, y viceversa desde UTF-16 a UTF-8 al recuperar resultados de Win32, en lugar de convertir cadenas internas UTF-8 de PHP hacia atrás la página de códigos OEM local (para las llamadas al sistema de archivos) o la página de códigos ANSI local (para todas las demás API de Win32, incluido el registro o el proceso).