大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

PHPでのリダイレクト

著者:北本 敦
公開日:2023/05/30
最終更新日:2023/08/31
カテゴリー:技術情報
タグ:

北本です。
タイトルが全く異なりますが、WebClientでのファイルダウンロードの続きです。

前回、WebClientでのファイルダウンロードについて扱いました。
そこでは、どこまで続いているのかわからない連番のファイルを一括でダウンロードするのに、WebClient.DownloadFileが404エラーによって例外を出すかどうかで終わりであるかを判断していましたが、その方法ではうまくいかない場合があると書きました。今回は、その例を紹介します。
一転してC#からPHPの話になります。PHPを扱うためのWebサーバ環境構築などについては以前の記事もご参照ください(今回はPHPのみでMySQLは使いません)。

以下のようなファイルを同一ディレクトリ内に用意します。

  • test.php
  • error.html
  • imageフォルダ

error.htmlの内容は適当で構いません。imageフォルダには前回の記事で示したような連番の画像ファイルを格納します。test.phpは以下のような内容にします。

test.php

<html>
<head><title>TEST</title></head>
<body>

<?php
$path = 'image/' . $_GET["image_name"];

if (file_exists($path))
{
	header('Location: ' .  $path);
} 
else
{
	header('Location: error.html');
}
exit;
?>
</body>
</html>

ローカルホストのポート番号8080をサーバーに使用し、上記のファイルをルートに配置している場合、ブラウザで以下のようなURLにアクセスしてみます。

http://localhost:8080/test.php?image_name=1_1.jpg

すると、imageフォルダ内に1_1.jpgが存在していれば、そのjpg画像が表示され、存在しない場合は、error.htmlが表示されるはずです。

コードの内容にも触れておきます。
以前の記事でも書きましたが、送信されたパラメータは、$_GETという変数に連想配列として格納されます。今回の場合、$_GET[“image_name”]という形でアクセスすると「1_1.jpg」が取得されます。
file_exists関数は、引数に指定したファイルが存在すればtrue、しなければfalseを返します。
header関数は、引数に「Location:URL」という形で指定することで、そのURLへのリダイレクトを行います。

では、このような場合に前回のような方法で連番画像をダウンロードしようとするとどうなるでしょうか?
下記のC#コードを実行します。前回から変更点は20行目のurlFormatの値だけです。

using System.IO;
using System.Net;

namespace ImageDownloader
{
    class Program
    {
        static void Main(string[] args)
        {
            // 実行ファイルのディレクトリ配下のdownloadフォルダを保存先とする
            string saveFolder = @"./download";
            if (!Directory.Exists(saveFolder))
            {
                // フォルダが存在しなければ作成
                Directory.CreateDirectory(saveFolder);
            }

            using (WebClient wc = new WebClient())
            {
                string urlFormat = @"http://localhost:8080/test.php?image_name={0}_{1}.jpg";

                int i = 1;  // 親番
                int j = 1;  // 枝番
                while (true)
                {
                    while (true)
                    {
                        string url = string.Format(urlFormat, i, j);
                        string fileName = string.Format(@"saved_image_{0}_{1}.jpg", i, j);
                        string saveFilePath = Path.Combine(saveFolder, fileName);
                        try
                        {
                            // ファイルをダウンロード
                            wc.DownloadFile(url, saveFilePath);
                        }
                        catch
                        {
                            // エラーでダウンロードできなかった場合、ファイルが存在しなかったものとみなしループを抜ける
                            break;
                        }

                        // 枝番を1つ進める
                        j++;
                    }

                    if (j == 1)
                    {
                        // 枝番「1」が存在しなかった場合、親番の最後の数を超えたとみなし終了
                        break;
                    }

                    // 親番を1つ進め、枝番を1に戻す
                    i++;
                    j = 1;
                }
            }
        }
    }
}

例えば、imageフォルダ内に1_1.jpg、1_2.jpg、1_3.jpgが存在し、1_4.jpg以降が存在しない場合に実行してみます。

結論から言うと、1_4.jpg以降を取得しようとしても404エラーが出ず、サーバーに接続できなくなるなどしてエラーでも出ない限り無限ループしてしまうことになります。
保存先のフォルダを見てみると、saved_image_1_4.jpg以降もしっかり出力されていますが、テキストエディタで開いてみるとその中身がerror.htmlの内容であることがわかります。
このように、ファイルが存在しない場合にリダイレクトされるようになっていると404エラーが出ないので、WebClient.DownloadFileの例外有無でファイルの存在を判定できないわけです。

次回はこの対策を考えてみます。

    上に戻る