PHP ZIP Archiv erstellen mit Umlauten

#1
Guten Tag liebe HaBo-User,

und zwar möchte ich mit PHP ein ZIP Archiv erstellen,... In das Archiv soll ein Verzeichnis (Inklusive Unterverzeichnisse),...

In den Verzeichnissen liegen nur PDF-Dateien, die allerdings Umlaute enthalten können. Meine bisherige Lösung sieht nach viel googlen momentan folgendermaßen aus:

PHP:
//Funktion
function zipDir(&$zip, $dir, $base = '')
{
 
  if (!file_exists($dir));
  $arFiles = scandir($dir);
 
  foreach ($arFiles as $file)
  {
 
    if (in_array($file, array('.', '..'))) continue;
    $x = iconv("UTF-8", "CP437", $file);
    if (is_file($dir.'/'.$file))
    {
        
      $zip->addFile($dir.'/'.$file,  $base.$x);
 
    }
    else if (is_dir($dir.'/'.$file))
    {
    
      $zip->addEmptyDir($base.$x);
      zipDir($zip, $dir.'/'.$file, $base.$x.'/');
 
    }
  }
}


//Aufruf
        $tmpzip = tempnam("/tmp", "datei");
        $id        = "1";
        $jahr     = "2014";
        
        // Objekt erstellen und schauen, ob der Server zippen kann
        $zip = new ZipArchive();
        if ($zip->open($tmpzip, ZIPARCHIVE::CREATE) !== TRUE) {
            die ("Archiv konnte nicht erstellt werden");
        }
        
        // Verzeichnisse
        zipDir($zip, './speicher/'.$id.'/'.$jahr.'/');
        

                     
        $zip->close();
                     
        header("Cache-Control: private");
        header('Content-Type: application/zip; charset=CP437');        
        header('Content-Disposition: filename='.$jahr.'.zip');   
        header("Pragma: public");
                 
        session_cache_limiter('nocache');
             
        die(file_get_contents($tmpzip));

Unter Windows werden die Umlaute nach dem entpacken korrekt angezeigt, bei Linux jedoch nicht,...

Ich erstelle das Zip auf einem Ubuntu 14.04 Server unter Apache.

Ich hoffe mir kann jemand helfen, oder eine alternative empfehlen - ich komme einfach nicht weiter.

MfG
Selig
 

SchwarzeBeere

Moderator
Mitarbeiter
#3
Unter Ubuntu musst du natürlich auch das Encoding richtig setzen. Welche Ausgabe hat denn

Code:
~$ locale
bei dir? Wenn die Dateinamen in CP437 stehen und du dort z.B. UTF-8 stehen hast, dann werden die Sonderzeichen natürlich falsch angezeigt. Unter Windows funktoniert es deshalb, weil Windows (FAT) CP437 als Dateinamen-Encoding nutzt, was ja auch im zip-File genutzt wird.

Beim arbeiten über mehrere OS bin ich bisher mit folgender Faustregel ganz gut gefahren: Überall UTF-8 verwenden.

edit: Ah, da war der Bitmuncher wohl schneller...
 
Zuletzt bearbeitet:
#4
Danke für die schnellen Antworten!

locale liefert bei mir folgendes zurück:

Code:
LANG=de_DE.utf8
LANGUAGE=de_DE.utf8
LC_CTYPE="de_DE.utf8"
LC_NUMERIC="de_DE.utf8"
LC_TIME="de_DE.utf8"
LC_COLLATE="de_DE.utf8"
LC_MONETARY="de_DE.utf8"
LC_MESSAGES="de_DE.utf8"
LC_PAPER="de_DE.utf8"
LC_NAME="de_DE.utf8"
LC_ADDRESS="de_DE.utf8"
LC_TELEPHONE="de_DE.utf8"
LC_MEASUREMENT="de_DE.utf8"
LC_IDENTIFICATION="de_DE.utf8"
LC_ALL=de_DE.utf8
Wie bekomm ich es hin, dass Windows dann mit UTF-8 Dateinamen was anfangen kann? Habt ihr zufällig noch irgendeinen Codeschnipsel rumliegen?

Grüße
Selig
 
#6
Guten Abend,

habe das ganze jetzt als UTF-8 versucht (so sind die Datei - und Ordnernamen ja unter Ubuntu?)

leider wird mir das ganze unter Windows und Ubuntu beim Entpacken wieder mit falschen Zeichen angezeigt (unter Windows wird aus einem ü "++" ) und unter Ubuntu ein anderes Zeichen,...

Stelle ich mich jetzt etwas dumm an?

Grüße
 
#8
Genau so:


PHP:
<?php
    $jahr     = "2014_15";
    $id        = "1";
    

        
        $tmpzip = tempnam("/tmp", "datei");
        
        
        // Objekt erstellen und schauen, ob der Server zippen kann
        $zip = new ZipArchive();
        if ($zip->open($tmpzip, ZIPARCHIVE::CREATE) !== TRUE) {
            die ("Archiv konnte nicht erstellt werden");
        }
        
        // Verzeichnisse
        zipDir($zip, './speicher/'.$id.'/'.$jahr.'/');
        

                     
        $zip->close();
                     
        header("Cache-Control: private");
        header('Content-Type: application/zip; charset=UTF-8');        
        header('Content-Disposition: filename='.$jahr.'.zip');   
        header("Pragma: public");
                 
        session_cache_limiter('nocache');
             
        die(file_get_contents($tmpzip));
        

/*******************   Funktionen ****************/

//Verzeichnis rekursiv verzippen
function zipDir(&$zip, $dir, $base = '')
{
 // iconv("ISO-8859-1", "CP437",
  if (!file_exists($dir));
  $arFiles = scandir($dir);
 
 //Dateien / Ordner abarbeiten
  foreach ($arFiles as $file)
  {
    
    if (in_array($file, array('.', '..'))) continue;
            
    if (is_file($dir.'/'.$file))
    {
    
      $zip->addFile($dir.'/'.$file,  $base.$file);
    }
    else if (is_dir($dir.'/'.$file))
    {
    
      $zip->addEmptyDir($base.$file);
      zipDir($zip, $dir.'/'.$file, $base.$file.'/');
 
    }
  }
}
?>
Habe auch schon Zeichenkodierung des Dateinamens ($file) automatisch erkennen lassen und nach UTF-8 konvertiert,... die Krypto-Zeichen bleiben allerdings die selben, was für mich heißt das es bereits UTF-8 ist,... aber weder Ubuntu auf der VM noch Windoof kommen damit klar -.-

EDIT:
Hab jetzt das ganze mal noch mit convmv getestet aber der hat mir folgendes ausgespuckt:
Code:
Starting a dry run without changes...
Skipping, already UTF-8: ./datei.pdf
^^ Bestätigt also, das meine Dateien im richtigen Zeichensatz vorliegen

was hat es damit aufsich? Ich habe aber PHP 5.5.9
https://bugs.php.net/bug.php?id=53948
 
Zuletzt bearbeitet:
#9
Guten abend zusammen,...

hab mir jetzt die folgende ZIP-Klasse besorgt:

Zip: Create archives of compressed files in ZIP format - PHP Classes

Diese vereinfacht meinen Code um einiges und bringt den UTF-8 Support mit,... (keine Ahnung wie, aber es funktioniert jetzt :D )

PHP:
        $zip = new Zip();
        //Verzeichnis zum Rekursiven Zippen anhängen
        $zip->addDirectoryContent("speicher/$id/$jahr");
        //Zip zum Download ausspucken
        $zip->sendZip("$jahr.zip");
^^ das war's - so einfach kann es sein =)

Grüße
Selig


EDIT:
Wenn mir noch jemand sagen kann, wie ich ohne eine externe klasse in PHP mit Umlauten zippen kann, würde ich mich freuen - aber das ist nur noch wegen der Neugier =)
 
Zuletzt bearbeitet:
Oben