fopen wrappers が有効の場合、WEB 上で配置するとそのサーバー以外の別のサーバにあるファイルを http 経由でいったん読み込んでからクライアントへ送ります。その際、ファイルサイズが必要になるので、readfile に先立って、cURL で、ファイルサイズだけを取得しています。 readfile はこのような処理に使う為の関数ですが、標準出力へ内容を出力するのでコマンドプロンプトで使う場合はファイルへリダイレクトする必要があります。なので、ここではコマンドプロンプトの場合は readfile を使用せずに通常のファイル処理としてファイルを書き込んでいます。 fget.php
<?php // ************************************************** // 【fget.php】 // http:// で他のサーバのファイルを読み込んでダウンロードします // 【利用方法】 // WEB : fget.php?target=URLエンコードされたURL&name=保存ファイル名 // CMD : 1) php.exe fget.php URL // CMD : 2) php.exe fget.php URL 保存ファイル名 // ************************************************** // ************************************************** // コマンドラインでも使えるように // ************************************************** if (substr(php_sapi_name(), 0, 3) == 'cgi') { $remoteFile = $_GET['target']; } else { $remoteFile = $argv[1]; } // 保存ファイル名をパスから作成 $fileName = basename($remoteFile); // 保存ファイル名を指定した場合 if (substr(php_sapi_name(), 0, 3) == 'cgi') { // WEBアプリで 保存ファイル名を指定 if ( isset($_GET['name']) ) { $fileName = $_GET['name']; } } else { // コマンドプロンプトで 保存ファイル名を指定 if ( isset($argv[2]) ) { $fileName = $argv[2]; } } // ************************************************** // PHP オンラインマニュアルの投稿データより // ファイルのサイズを取得する cURL の処理 // ************************************************** $ch = curl_init($remoteFile); curl_setopt($ch, CURLOPT_NOBODY, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); if ( substr( $remoteFile, 0, 5 ) == "https" ) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); } $data = curl_exec($ch); curl_close($ch); if ($data === false) { echo 'cURL failed'; exit; } $contentLength = 'unknown'; $status = 'unknown'; if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches)) { $status = (int)$matches[1]; } if (preg_match('/Content-Length: (\d+)/', $data, $matches)) { $contentLength = (int)$matches[1]; } // ************************************************** // WEB 経由ダウンロード // ************************************************** if (substr(php_sapi_name(), 0, 3) == 'cgi') { header( "Content-Type: application/octet-stream" ); header( "Content-disposition: attachment; filename={$fileName}" ); $path = $remoteFile; header( "Content-Length: $contentLength" ); readfile($path); exit(); } // ************************************************** // Windows コマンドライン // Windows では、fopen()の mode パラメータに 'b' を // 指定してファイルをオープンする必要があります。 // ************************************************** else { $ihandle = fopen($remoteFile, "rb"); $ohandle = fopen($fileName, "wb"); if ( $ihandle ) { while( !feof($ihandle) ) { $ret = fread( $ihandle, 1024 ); fwrite( $ohandle, $ret ); } fclose( $ohandle ); fclose( $ihandle ); } exit(); } ?>
関連する情報 PHP fread fread の第二引数は、読み込む最大バイトなので、EOF に達すると、それ以内のデータが取得されます。 PHP fwrite 大きなファイルですと、問題が出るという報告もあるので、その場合は以下のように readfile を書き換えるといいかもしれません。 Streaming a large file using PHP Problem with download of larger files
|
【PHP + 通信の最新記事】
- fake sendmail for windows を使って、PHP でごく普通に( mb_send_mail で )メール送信
- PHP の cURL でファイルアップロード
- PHP : cURL : Google Photo API の albums.list メソッドを使用して アルバム一覧データを取得する
- PHP + cURL で Google Photo API の アクセストークンを取得する
- PHP : cURL で FTP + SSL ダウンロード
- PHP の imap 関数で( Windows ローカル )、Yahoo メールのメールをさくらインターネットのメールへコピーする
- PHP の imap 関数( Windows のローカル )で、さくらインターネットのメールボックスの情報を取得する
- PHP : IMAP 関数 でまずメールのヘッダ部分を整理してログに出力する / ※ JSON 出力を追加
- ファイルを一つアップロード : FORM の target を IFRAME にして、PHP に JavaScript を書き出させて元のページにメッセージを表示させる
- Pear の Net_POP3 で、SSL(995) を使って簡単にメール受信
- PHP をコマンドプロンプトから実行して、WEB 上のデータを取得するいくつかの方法
- FormData を使用して $.ajax で送信すると、ファイルのアップロードとメール送信(ファイル添付)を一度に行えます
- ファイルのアップロードからそれを添付してメールを送るテンプレート(スケルトン)
- PHP : mb_send_mail を使用した自家用メール送信 API
- PHP で Windows標準のオブジェクト(CDO.Message)とGMail を使ってメール送信
- PHP : http 経由でファイルのサイズを取得する file_size 関数と ファイルサイズを付加した get_imagesize 関数
- 連想配列のキー部分がプロパティと一致したらセットする( メール送信用クラス )
- PHP : リモートのファイルサイズを取得する
- ローカルの PHP を使ってコマンドプロンプトより簡単にバイナリファイルをアップロードする
- PHP の cURL で ftp サーバーにファイルをアップロードする(SSLなし)