31 votes

glob () ne trouve pas les noms de fichiers avec des caractères multi-octets sous Windows?

Je suis en train d'écrire un gestionnaire de fichiers et de numériser des répertoires et de traiter avec le renommage de fichiers qui peuvent avoir des caractères multioctets. Je travaille en local sur Windows/Apache PHP 5.3.8, avec les noms de fichiers dans un répertoire:

  • filename.jpg
  • имяфайла.jpg
  • file件name.jpg
  • פילענאַמע.jpg
  • 文件名.jpg

Des tests sur un serveur UNIX woked amende. Tester en local sur Windows à l'aide d' glob('./path/*') ne retourne que le premier, filename.jpg.

À l'aide de scandir(), le bon nombre de fichiers est retourné au moins, mais j'ai des noms comme ?????????.jpg (note: ceux-ci sont régulièrement des points d'interrogation, pas la � caractère.

Je vais finir par avoir besoin d'écrire une fonction de recherche pour rechercher récursivement par le biais de l'ensemble de l'arborescence pour les noms de fichiers correspondant à un modèle ou à une certaine extension de fichier, et j'ai supposé glob() serait le bon outil pour cela, plutôt que de scanner tous les fichiers et de faire le filtrage et la matrice de la construction dans le code de l'application. Je suis ouvert à des propositions de remplacement en cas de besoin.

En supposant que c'était un problème courant, j'ai immédiatement cherché sur Google et de Débordement de Pile et n'a rien trouvé, même relative. Est-ce un Windows question? PHP lacune? Quelle est la solution: est-ce que je peux faire?

Addendum: vous ne savez Pas comment liées à ce qui est, mais l' file_exists() est également de retour en FALSE de ces fichiers, en passant en plein de chemin d'accès absolu (à l'aide de Notepad++, le fichier php en lui-même est l'encodage UTF-8 sans BOM). Je suis certain que le chemin d'accès est correct, en tant que voisins des fichiers sans caractères multioctets retour TRUE.

EDIT: glob() peut trouver un fichier nommé filename-äöü.jpg. Auparavant, dans ma .htaccess le fichier, j'ai eu AddDefaultCharset utf-8, que je n'ai pas pensé avant. filename-äöü.jpg a l'impression qu' filename-���.jpg. Le seul effet d'enlever cette htaccess la ligne semblait avoir était maintenant que le nom de fichier s'imprime normalement.

J'ai supprimé l' .htaccess le fichier complètement, et c'est bien mon script de test dans son intégralité (j'ai changé quelques noms de fichier à partir de l'original post):

print_r(scandir('./uploads/')); 
print_r(glob('./uploads/*'));

Sortie en local sur 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
)

Sortie à distance sur un serveur 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
)

Puisque c'est un serveur différent, indépendamment de la plate - forme de configuration pourraient être différents, donc je ne sais pas quoi penser, et je ne peux pas entièrement épingler sur Windows (peut-être mon installation de PHP, des paramètres ini, ou de configuration d'Apache). Des idées?

7voto

virmaior Points 233

Il ressemble à la fonction glob() dépend de la façon dont votre copie de PHP a été construit et qu'il a été compilé avec une unicode-connaissance de l'API WIN32 (je ne crois pas que la norme builid est.

Cf. http://www.rooftopsolutions.nl/blog/filesystem-encoding-and-php

Extrait de commentaires sur l'article:

Philippe Verdy 2010-09-26 8:53 am

La sortie de votre installation de PHP sur Windows est facile à expliquer : vous avez installé la mauvaise version de PHP, et a utilisé une version non compilé pour utiliser la version Unicode de l'API Win32. Pour cette raison, le système de fichiers appelle utilisé par PHP va utiliser l'héritage "ANSI" API les bibliothèques C/C++ lié avec cette version de PHP va d'abord essayer de convertir vos codé en UTF-8 PHP chaîne dans le local "ANSI" codepage sélectionné dans l'environnement en cours d'exécution (voir la RSSA de commande avant départ PHP à partir d'une fenêtre de ligne de commande)

Votre version de Windows n'est PROBABLEMENT PAS responsable de cette étrange chose. En fait, c'est VOTRE version de PHP qui n'est pas compilé correctement, et qui utilise l'héritage ANSI version de l'API Win32 (pour la compatibilité avec le legs de la 16-bits de Windows 95/98 dont support du système de fichiers dans le noyau avait en fait pas de support direct pour L'Unicode, mais utilisés à l'interne une couche de conversion pour convertir Unicode le local de page de codes ANSI avant d'utiliser la réelle version ANSI de la API).

Recompiler PHP avec l'option de compilateur à utiliser la version UNICODE de l'API Win32 (ce qui devrait être le défaut aujourd'hui, et de toute façon toujours la valeur par défaut de PHP installé sur un serveur qui ne sera JAMAIS Windows 95 ou Windows 98...)

Ensuite, Windows sera capable de stocker codé en UTF-16 noms de fichiers (y compris les sur les volumes FAT32, même si, sur ces volumes, il permettra également de générer un alias de nom court au format 8.3 utilisant le système de fichiers par défaut page de codes, quelque chose qui peut être évité dans les volumes NTFS).

Tout ce que vous décrivez sont des problèmes de PHP (un mauvais portage à Windows ou version incorrecte du système d'identification au moment de l'exécution) : relire les fichiers lisez-moi venir avec PHP sources expliquant l' indicateurs de compilation. Je pense vraiment que le makefile sur Windows devrait être capable de configurer et de détecter automatiquement si il a vraiment besoin d'utiliser SEULEMENT la ANSI version de l'API. Si vous compilez pour un serveur, faire assurez-vous que le script Configure va détecter efficacement le plein support de l'UNICODE version de l'aPI Win32 et va l'utiliser quand la compilation de PHP et lors de la sélection du runtime des bibliothèques de lien.

J'utilise le PHP sur Windows, correctement compilé, et je NE suis absolument PAS savoir les problèmes que vous citez dans votre article.

Oublions maintenant à jamais ces non-UNICODE versions de Win32 API (qui sont à l'aide de inconsistantly les locaux de page de codes ANSI pour la Windows INTERFACE utilisateur graphique, et la page de codes OEM pour le système de fichiers Api, le DOS/BIOS-compatible Api, la Console des Api) : ces non-Unicode les versions de l'Api sont même BEAUCOUP plus lent et plus coûteux que les Unicode versions de l'Api, parce qu'ils sont en fait la traduction la page de codes Unicode avant à l'aide de la base de l'Unicode des Api (l' situation sur Windows NT noyaux est exactement l'inverse de la situation sur les versions de Windows basé sur un virtual DOS extender, tels comme Windows 95/98/ME).

Lorsque vous n'utilisez pas la version native de l'API, votre appel d'API passer par l'intermédiaire d'un médiateur de la couche qui va convertir les chaînes de caractères entre Unicode et celui de l'héritage de l'ANSI ou RSSA-sélectionné OEM pages de code, ou la page de codes OEM allusion sur le système de fichiers: ceci requiert de la temporaire d'allocation de mémoire dans le non-natif version de Win32 L'API. Cela prend plus de temps pour convertir des choses avant de faire le travail réel en appelant l'API native.

En résumé: PHP vous installer sur Windows DOIT être différent selon si vous avez compilé pour Windows 95/98/SE (ou l'ancien Win16s couche d'émulation pour Windows 3.x, qui avait un très mimimum support de l'UTF-8, uniquement à l'appui de l'Unicode des sous-ensembles de l'Unicode utilisé par l'ANSI et OEM codapges sélectionné lors du démarrage de Windows à partir d'un DOS extender) ou s'il a été compilé pour toute autre version de Windows sur le noyau de windows NT.

La meilleure preuve que c'est un problème de PHP et pas Windows, c'est que vos résultats bizarres ne se produira PAS dans d'autres langages tels que C#, Javascript, VB, Perl, Ruby, PHP... a une très mauvaise histoire dans le suivi les versions (et beaucoup trop d'historique code source de bizarreries et de mal des hypothèses qui devraient être désactivé aujourd'hui, et un incompatible bibliothèque qui a hérité de toutes ces bizarreries d'abord fait dans les anciennes versions de PHP pour les anciennes versions de Windows qui sont même n'est plus officiellement soutenu par Microsoft ou même par PHP lui-même !).

En d'autres termes : RTFM ! Ou de télécharger et installer une version binaire de PHP pour Windows precompield avec les paramètres corrects : je pense vraiment que PHP doit distribuer des binaires pour Windows déjà compilé par par défaut pour la version Unicode de l'API Win32, et à l'aide de la Version Unicode de la bibliothèques C/C++: en interne, le code PHP sera convertir ses chaînes UTF-8 UTF-16 avant l'appel de l'API Win32, et de retour de l'UTF-16 pour de l'UTF-8 lors de la récupération Win32 résultats, au lieu de la conversion de PHP interne des chaînes UTF-8 arrière/vers le local de page de codes OEM (pour le système de fichiers d'appels) ou encore la page de codes ANSI (pour tous les autres Win32 Api, y compris le registre ou d'un processus).

-1voto

CarcaBot Points 19

essayer

 <?php
header('Content-Type: text/html; charset=iso-8859-1'); // or charset=utf-8');
print_r(glob('./uploads/*'));
?>
 

-1voto

relu Points 48

Essayez de définir mb_internal_encoding () sur " UTF-8 " avant d'utiliser glob

 mb_internal_encoding("UTF-8");
print_r(glob('./uploads/*'));
 

-1voto

Mihai Popescu Points 11

Je n'ai pas touché PHP pour les 3 ou 4 ans maintenant, mais peut-être cela peut vous aider :

pathinfo() est locale au courant, donc pour pouvoir analyser un chemin contenant des caractères multioctets correctement, la mise en correspondance locale doit être défini à l'aide de la fonction setlocale()

Et quelques liens directs:

pathinfo - lire la deuxième note

à propos de la fonction setlocale

(Je pense que votre problème vient de la numérisation de l'répertoires, et non pas à partir de l'écran de code de soi ou de les en-têtes, depuis Chrome ou firefox, si je me souviens bien, peut gérer Unicode caractères.)

-1voto

Pierre Points 560

PHP sous Windows n'utilise pas encore l'API Unicode. Vous devez donc utiliser l'encodage d'exécution (quel qu'il soit) pour pouvoir gérer les charset non ascii.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X