質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.96%

ディレクトリを丸ごとzipでダウンロードしたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 6,038
退会済みユーザー

退会済みユーザー

よろしくお願いします。

ディレクトリをまるごとzipでダウンロードしたいです。

Windows8.1
php 5.4.39
Apache 2.2.14
localでの実行です。

ziptest
|
|-mysite
|   |-image
|   |   |-image1.png
|   |-file1.php
|   |-file2.php
|
|-exe.php(zipに圧縮する処理が書かれたファイル。これを実行する。)

上記が私の環境です。

やりたいことですが、mysiteの中身を丸ごとzipで圧縮してダウンロードをしたいという事です。

mysite
|
|-image
| |-image1.png
|
|-file1.php
|-file2.php

上記のような状態のものを、zipで圧縮してダウンロードすることが目標です。

現状ですが、

mysite/image(imageフォルダ)を消した場合、
(以下、パターン1)
mysite.zip
|
|-mysite
| |-file1.php
| |-file2.php
|
|-file1.php
|-file2.php

このような形でzipが出来上がりました。

ちなみに、

$zip->addFromString($filename,file_get_contents($filepath));
こちらをコメントアウトした状態で実行すると、
(以下、パターン2)
mysite.zip
|
|-mysite
| |-file1.php
| |-file2.php

このような形でzipで出来上がります。

どちらにせよ、imageフォルダが存在していると圧縮が出来ません。
どこが原因になっているのでしょうか?

以下にコードを記載します。

<php

//Zipクラスロード
$zip = new ZipArchive();

//Zipファイル名指定
$zipFileName = 'mysite.zip';

//Zipファイル一時保存ディレクトリ取得
$zipTmpDir = '/phpdocs/nonprothemes';

//Zipファイルオープン
$result = $zip->open($zipTmpDir.$zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);

if ($result !== true) {
    return false;
}

//処理制限時間を外す
set_time_limit(0);


/* ファイルパスを指定する処理 */

//mysite内のファイル一覧取得
//ディクトリパス格納用変数
$dir = null;
$dir = 'mysite/';

//ハンドル取得用変数
$handle = null;
//ファイル情報取得用変数
$file = null;
//ファイルパス指定用配列
$fpath_array = array();

//ディレクトリの存在確認、ハンドル取得
if(is_dir($dir) && $handle = opendir($dir))
{
    //ディレクトリ内のファイルを取得
    while(($file = readdir($handle)) !== false)
    {
        //'.','..'を取り除く処理
        if($file != "." && $file != "..")
        {
            //ファイルパス指定
            $fpath_array[] = 'mysite/'.$file;
        }
    }
}

//ファイルパス指定
//$fpath_array = array('mysite/style.css','mysite/index.php');
/* ここまで */

//Zip追加処理
foreach ($fpath_array as $filepath) {
    //filename取得
    $filename = basename($filepath);

    //取得ファイルをZipに追加
    $zip->addFromString($filename,file_get_contents($filepath));
    $zip->addFile($filepath);
}

$zip->close();

// ストリームに出力
header('Content-Type: application/zip; name="' . $zipFileName . '"');
header('Content-Disposition: attachment; filename="' . $zipFileName . '"');
header('Content-Length: '.filesize($zipTmpDir.$zipFileName));
echo file_get_contents($zipTmpDir.$zipFileName);

// 一時ファイルを削除しておく
unlink($zipTmpDir.$zipFileName);
?>

どこが原因になっているでしょうか?
よろしくお願いします。

/***** 追記 ******/
回答してくださった方の意見を元に、コードを修正しました。
結果、中身の無いzipが出来上がりました。
ただ、zipフォルダはサイズが8KBあります。
どういう状況なのか見当がつきません。
原因について分かることがあれば意見をお願いしたいです。

$dist = 'mysite.zip'; // 生成する圧縮ファイル名
$path = './mysite'; // 圧縮するパス
$zipTmpDir = '/phpdocs/nonprothemes'; // 一時パス


$zip = new ZipArchive();
$zip->open($zipTmpDir.$dist, ZipArchive::CREATE | ZipArchive::OVERWRITE);
addZip($zip, $path);
$zip->close();

function addZip($zip, $path) {
  if (is_dir($path)) {
    $files = array_diff(scandir($path), ['.', '..']);
    foreach ($files as $file) addZip($zip, "$path/$file");
  } else {
    $zip->addFile($path);
  }
}

// ストリームに出力
header('Content-Type: application/zip; name="' . $dist . '"');
header('Content-Disposition: attachment; filename="' . $dist . '"');
header('Content-Length: '.filesize($zipTmpDir.$dist));
echo file_get_contents($zipTmpDir.$dist);

// 一時ファイルを削除しておく
unlink($zipTmpDir.$dist);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

check解決した方法

0

自己解決することが出来ました。
皆様回答ありがとうございました。

全てのファイルパスを、

圧縮したいフォルダ名/(サブフォルダ名)/ファイル名

このように統一して1つの配列にまとめ、addFileでzipに追加、圧縮という形になっています。
サブフォルダはいくつあっても問題ありませんでした。
空のサブフォルダが存在していてもエラーは出ません。
しかし、圧縮したzipには空のサブフォルダは作られません。
以下がコードです。

<?php

//Zipクラスロード
$zip = new ZipArchive();

//Zipファイル名指定
$zipFileName = 'mysite.zip';

//Zipファイル一時保存ディレクトリ取得
$zipTmpDir = '/phpdocs/nonprothemes';
$path = './mysite';
$path2 = 'mysite';

//Zipファイルオープン
$result = $zip->open($zipTmpDir.$zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);

if ($result !== true) {
  return false;
}

//処理制限時間を外す
set_time_limit(0);

//パス取得
$fpath_array_beta = array_diff(scandir($path), ['.', '..']);

// zip追加する本命のパスを格納する配列
$fpath_array = array();

// ディレクトリ判別
foreach ($fpath_array_beta as $key => $value) {
  if(is_dir("$path/$value")){
    // パス指定
    $path_sub = "$path/$value";
    // サブフォルダ内のファイル名取得
    $array_beta = array_diff(scandir($path_sub), ['.', '..']);
    // パスとして取得(元配列に追加)
    foreach ($array_beta as $key2 => $value2) {
      array_push($fpath_array,"$path2/$value/$value2"); 
    }
  }else{
    // ファイルの場合はそのまま追加
    array_push($fpath_array,"$path2/$value");
  }
}

// print "<pre />"; var_dump($fpath_array); print "<pre />";

//Zip追加処理
foreach ($fpath_array as $filepath) {
  $zip->addFile($filepath);
}

$zip->close();

// ストリームに出力
header('Content-Type: application/zip; name="' . $zipFileName . '"');
header('Content-Disposition: attachment; filename="' . $zipFileName . '"');
header('Content-Length: '.filesize($zipTmpDir.$zipFileName));
echo file_get_contents($zipTmpDir.$zipFileName);

// 一時ファイルを削除しておく
unlink($zipTmpDir.$zipFileName);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

今、お試し環境が手元に無いので具体的な修正例をご提示出来ませんが・・・

ZipArchiveクラスでディレクトリツリー全体を固めたい場合は、ファイル追加前に都度、親ディレクトリを明示的に追加してやる必要があります。
つまり、今のケースでは image ディレクトリを追加してから image1.png を追加します。

ZipArchive クラス

ですが、ディレクトリ階層が深い場合はとても面倒なので、適材適所でLinuxコマンドを併用する方法がおすすめです。
詳細は下記ページをご参照ください。

PHPからフォルダ構成ごとzip圧縮

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

再帰を使って書くとこんな感じです。
$pathにはファイルでもディレクトリでも指定出来ます。

<?php
$dist = 'test.zip'; // 生成する圧縮ファイル名
$path = './test'; // 圧縮するパス

$zip = new ZipArchive();
$zip->open($dist, ZipArchive::CREATE | ZipArchive::OVERWRITE);
addZip($zip, $path);
$zip->close();

function addZip($zip, $path) {
  if (is_dir($path)) {
    $files = array_diff(scandir($path), ['.', '..']);
    foreach ($files as $file) addZip($zip, "$path/$file");
  } else {
    $zip->addFile($path);
  }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/18 07:33 編集

    回答ありがとうございます。
    試してみたところzipの中身が空の状態だったのですが原因は何が考えられるでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る