5

最終目標:1ページのリンクをクリックして、ファイルをダウンロードし、ページ1を更新します。PHPを使用して、パブリックhtmlにないダウンロードを提供します。

アプローチ:

ページ1。 リンクはページ2に移動し、使用しているファイルの変数参照を取得します。

ページ2。 ページ1を更新する前に更新する必要がある情報で関連するSQLデータベースを更新します。「firstpass」セッション変数を設定します。get変数からセッション変数「getvariablereference」を設定します。1ページにリダイレクトします。

ページ1。 初回通過セッション変数が設定されている場合。セカンドパスセッション変数を設定します。初回通過変数の設定を解除します。ページの更新。リロード時に、更新されたSQLデータベース情報(2ページで変更)を使用してページが再構築されます。

ページ1を更新 しました。2回目のパスセッション変数が設定されている場合。ダウンロードサービングヘッダーシーケンスを実行します。

これはページ1です。最初のリンクがあるページ1の部分は表示していません。関係ないので。

// REFERSH IF FIRSTPASS IS LIVE
if ($_SESSION["PASS1"] == "YES"){
    $_SESSION["PASS1"] = "no";
    $_SESSION["PASS2"] = "YES";
    echo "<script>document.location.reload();</script>";
    }
if ($_SESSION["PASS2"] == "YES"){
    // Grab reference data from session:
        $id = $_SESSION['passreference'];
                // Serve the file download
                        //First find the file location
                        $query = "SELECT * from rightplace
                              WHERE id = '$id'";
                        $result = mysql_query($query);
                        $row = mysql_fetch_array($result);
                        $filename = $row['file'];
                        $uploader = $row['uploader'];   
                            // Setting up download variables
                                $string1 = "/home/domain/aboveroot/";
                                $string2 = $uploader;
                                $string3 = '/';
                                $string4 = $filename;
                                $file= $string1.$string2.$string3.$string4;
                                $ext = strtolower (end(explode('.', $filename)));
                                //Finding MIME type
                                    if($ext == "pdf" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/pdf');
                                        readfile($file);
                                        }                                   
                                    if($ext == "doc" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/msword');
                                        readfile($file);
                                        }                   
                                    if($ext == "txt" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: text/plain');
                                        readfile($file);
                                        }                   
                                    if($ext == "rtf" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/rtf');
                                        readfile($file);
                                        }
                                    if($ext == "docx" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
                                        readfile($file);
                                        }
                                    if($ext == "pptx" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/vnd.openxmlformats-officedocument.presentationml.presentation');
                                        readfile($file);
                                        }
                                    if($ext == "ppt" && file_exists($file)) {
                                        header("Content-disposition: attachment; filename= '$filename'");
                                        header('Content-type: application/vnd.ms-powerpoint');
                                        readfile($file);
                                        }
                                        }

2ページのスクリプトは正しく機能しています。SQLデータベースを更新し、メインページに適切にリダイレクトします。また、「$ _SESSION['passreference'];」が設定されていることも確認しました。正しく、1ページの何もそれを設定解除しません。

だから、それは状況の全体の長い説明です。私は困惑しています。何が起こるかというと、私が言ったように、2ページはうまく機能します。次に、ページ1に移動し、更新してからダウンロードをプッシュしません。ダウンロードスクリプトが機能し、ファイルがダウンロードされることを知っています(更新シーケンス全体なしでチェックされます)。

基本的に2つの質問があります。

  1. 誰かが何がうまくいかないのかを見つけることができますか?

  2. 誰かがより良いアプローチを概念化できますか?

4

3 に答える 3

6

コードが与えられたとしても、このようなものをリモートでデバッグすることは困難です。投稿したセグメントは、あなたが言うように機能します。エラーログを確認しましたか?最も可能性の高い原因は、header()他の出力が行われた後に送信する際の問題です。

ファイルのダウンロードを処理するときは、新しいページ/ウィンドウでダウンロードを開始する方が簡単であるため、ヘッダーが破損するリスクはないと思います。実際のダウンロードを開始する3番目のページを使用して、シーケンスを少し変更した可能性があります。

  1. ページ1は、魔法を実行するために2番目のページにリンクします。これにより、ページ1にリダイレクトされます。
  2. 次に、ページ1が新しいウィンドウにページ3を生成し、ダウンロードが開始されます。

この回答には、ダウンロード用の新しいウィンドウをロードするための良いサンプルコードがあります。

于 2012-08-08T01:07:45.823 に答える
3

コードを見ると、ダウンロードの問題は、$ext変数に予期しない値が含まれていること、または$file変数に実際には存在しないファイルの名前が含まれていることである可能性があります。
どちらの場合も、「if」条件はいずれも当てはまらないため、ダウンロードは開始されません。私の提案は、" "コメント行
の直前に次のステートメントを追加することです。//Finding MIME type

$log  = "file='".$file."'\n";
$log .= "ext='".$ext."'\n";
@file_put_contents("/tmp/page1.log", $log, FILE_APPEND);

このように、「/ tmp / page1.log」ファイルを見ると、変数と変数に期待値が効果的に含まれているかどうかを確認できるはず$fileです$ext
Linuxで作業していると思われるので、ログファイル名として「/tmp/page1.log」を使用しました。そうでない場合は、「file_put_contents」関数の最初の引数を、環境の有効なパスとファイル名で調整してください。
また、「if」テストのシーケンスを次のコードに置き換えます。

$content_types = array(
    "pdf"  => "application/pdf",
    "doc"  => "application/msword",
    "txt"  => "text/plain",
    "rtf"  => "application/rtf",
    "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation"
);

if (isset($content_types[$ext])) {
    if (file_exists($file)) {
        header("Content-disposition: attachment; filename= '$filename'");
        header('Content-type: '.$content_types[$ext]);
        readfile($file);
        die("");
    } else {
        die("** '".$file."' does not exist **");
    }
} else {
    die("** Unhandled '".$ext."' extension **");
}

明らかに、私が行ったように単に「die()」関数を使用するのではなく、はるかに堅牢な方法でエラー処理を実装する必要がありますが、これは単なる例です。
最後に、ファイル拡張子に対応するコンテンツタイプを取得するためのより良い方法もあることに注意してください。たとえば、1つの解決策は、PHPFileinfo関数を使用することです。このトピックの詳細については
この回答をご覧ください。セーフモード
では、file_exists関数は常にFALSEを返し、file_exists関数の結果はキャッシュされることにも注意してください。詳細については、PHPマニュアルのclearstatcache()関数を参照してください。

于 2012-08-09T20:55:39.000 に答える
0

PHPコードを少し作り直しました。特に、何がうまくいかないかについてのより多くの情報を得るでしょう。このコードを試して、新しいエラーメッセージのいずれかが表示された場合は、何が起こったかを説明する次のコメントを読んでください。また、以下の注の部分も読んでください。これは、ファイルが存在し、正しいディレクトリにある場合でも、PHPからファイルにアクセスできない理由を説明しています。

  1. window.location.reload();を使用する document.location..の代わりに
  2. error()関数を追加しました。HTMLを追加して、必要なレイアウトのページを作成できます。また、エラーをローカルファイルに記録することもできます。機密情報をデータベースエラー(SQLを含む場合があります)として関数に渡すために使用されるプライベート情報パラメーターがあります。生産的に使用するために、それをユーザーに表示しないでください。代わりに、ファイルにログインするか、特権ユーザー(管理者など)に対してのみ表示することができます。
  3. 天気$idが設定されていることを確認します。そうでない場合はerror()メッセージを返します。セッションが正しく更新されなかった場合に発生する可能性があります。
  4. 「$id= addlashes($ id);」を追加しました セキュリティ上の理由から。たとえば、IDを$ id = "'OR 1"(SQL-Injection)のような値に設定できると、問題が発生する可能性があります。これが発生しないことが確実な場合は、削除できます。
  5. DBクエリの後に$result変数をチェックします。たとえば、データベース接続が確立されていない場合、またはスクリプトが接続できない場合、これはエラー()出力を生成して通知します。SQL構文にエラーがある場合、たとえばテーブル名が間違っている場合も同じことが起こります。
  6. また、有効な$rowがデータベースからフェッチされているかどうかもチェックされます。返された行がない場合は、$ idが間違っている可能性があります(データベースにそのようなエントリはありません)。
  7. 文字列操作を$filepath=$rootpathに書き直しました。"/"。$uploader。"/"。$ filename; ここで、$ rootpathは、末尾に「/」を付けずに前に設定されています。これは読みやすいです...
  8. 拡張機能とMIMEタイプは、多くの「if-then」ブロックを使用する代わりに配列に配置されるようになり、保守が容易になりました。また、そのブロック内のコードも同様でした...したがって、1回だけ記述する必要があります。
  9. ファイル拡張子が不明な場合は、デフォルトのMIMEタイプ(Content-Type: "application / octet-stream)が送信されます。
  10. file_exists()をチェックし、エラーメッセージを出力します。パスが正しい天気をチェックできるように$filenameを指定します...

ソースコードは次のとおりです。

<?php 

function error($message, $info = "") {
  echo "ERROR: $message<br>";
  echo "PRIVATE-INFO: $info"; // probably you only want to log that into a file?
  exit;
}

// REFERSH IF FIRSTPASS IS LIVE
if ($_SESSION["PASS1"] == "YES") {
  $_SESSION["PASS1"] = "no";
  $_SESSION["PASS2"] = "YES";
  echo "<script>window.location.reload();</script>";
  exit;
}


if ($_SESSION["PASS2"] == "YES") {
  // Grab reference data from session:
  $id = $_SESSION['passreference'];

  if (!$id) error("Internal Error ('id' not set)");

  // Select file location from DB
  $id = addslashes($id);
  $query = "SELECT * from rightplace WHERE id = '$id'";
  $result = mysql_query($query);

  if (!$result) error("DB-query execution error", mysql_error());

  $row = mysql_fetch_array($result);
  mysql_free_result($result);

  if (!$row) error("File with ID '$id' was not found in DB.");

  $filename = $row['file'];
  $uploader = $row['uploader'];

  // Setting up download variables
  $rootpath = "/home/domain/aboveroot";
  $filepath = $rootpath . "/" . $uploader . "/" . $filename;
  $ext = strtolower(end(explode('.', $filename)));

  // Serve the file download

  // List of known extensions and their MIME-types...
  $typelist = array(
      "pdf"  => "application/pdf",
      "doc"  => "application/msword",
      "txt"  => "text/plain",
      "rtf"  => "application/rtf",
      "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      "pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
      "ppt"  => "application/vnd.ms-powerpoint"
  );

  // set default content-type
  $type = "application/octet-stream";

  // for known extensions, assign specific content-type
  if (!isset($typelist[$ext])) $type = $typelist[$ext];

  if (file_exists($filepath)) {
    header("Content-disposition: attachment; filename= '$filename'");
    header("Content-type: $type");
    readfile($filepath);
  } else {
    error("Error: File '$filepath' was not found!", $filepath);
  }
}

?>

ノート:

  1. ファイルが存在する場合でも、ファイルが見つからないというエラーが発生する可能性があります。これが発生した場合、これはおそらく、PHPスクリプトがHTMLルートディレクトリ外のファイルにアクセスするのを防ぐセキュリティメカニズムです。たとえば、phpスクリプトは、ルートディレクトリ「/」が「/ home /username/」などにマップされる「chrooted」環境で実行できます。したがって、「/ home / username / dir / file」にアクセスする場合は、PHPスクリプトに「/ dir/file」と記述する必要があります。ルートが「/home/ username / html」のように設定されている場合は、さらに悪化する可能性があります。そうすると、「html」ディレクトリの下のディレクトリにアクセスできなくなります。これを回避するには、HTMLルート内にディレクトリを作成し、そこに「.htaccess」という名前のファイルを配置します。その中に「DENYFROMALL」と書いてください。これにより、ブラウザの要求によるディレクトリへのアクセスが防止されます(スクリプトのみがディレクトリにアクセスできます)。これは、Apacheサーバーでのみ機能します。しかし、他のサーバーソフトウェアにもそのような解決策があります...これに関する詳細は以下にあります:http://www.php.net/manual/en/ini.core.php#ini.open-basedir

  2. もう1つの可能性は、(アップロードされたファイルの)ファイルアクセス権が設定されておらず、スクリプトがそれらにアクセスできるようになっていることです。一部のセキュリティ設定を有効にすると(Linuxサーバーで)、PHPスクリプトは、スクリプトファイルに設定された「所有者」と同じユーザーが所有するファイルにのみアクセスできます。「ftp」経由でアップロードした後、これはおそらくftpユーザーのusersnameです。シェルで編集した場合、これは現在のユーザーのユーザー名になります。=>しかし:アップロードされたファイルは、Webサーバーが実行されているユーザーに割り当てられることがあります(「www-data」、「www-run」、「apache」など)。それで、それがどれであるかを見つけて、あなたのスクリプトをこの所有者に割り当ててください。

  3. ファイルのアップロードには、ここで説明されているmove_uploaded_file(...)を使用する必要があります:www.php.net/manual/en/function.move-uploaded-file.php; これを行わないと、ファイルアクセス権が間違っているか、ファイルにアクセスできない可能性があります。
于 2012-08-15T13:56:07.917 に答える