PHP ファイルアップロードのソースコード分析 (RFC1867) 知りたい人は参考にしてください
HTTP ベースのアップロードは、FTP よりも比較的使いやすく、安全です。この記事では、PUT、WEBDAV、RFC1867 などのアップロード方法を分析します。 PHP で RFC1867 に基づいたファイル アップロードを実装するための
RFC1867
RCF1867 は、HTML 標準プロトコルのフォームベースのファイル アップロードです。
1 type 属性にファイル オプションを追加しました。入力要素の。
2 input タグには、アップロードできるファイル タイプまたはファイル形式のリストを指定できる accept 属性を含めることができます。
さらに、この標準では、新しい MIME タイプ multipart/form-data も定義されており、enctype="multipart/form-data" または を含むファイルを処理する場合、フォームにマークを付けるときに取るべき動作。
たとえば、HTML でユーザーが 1 つ以上のファイルをアップロードできるようにしたい場合は、次のように記述できます:
このフォームは誰もがよく知っているはずですが、PHP では独自の定義があります。デフォルトのフォーム要素 MAX_FILE_SIZE。ユーザーは、この非表示のフォーム要素を使用して、PHP がアップロードするファイルの最大サイズのみを許可することを提案できます。たとえば、上記の例では、ユーザーがアップロードするファイルが 5000 (5k) を超えないようにすることができます。 ) バイトの場合、次のように記述できます:
この MAX_FILE_SIZE がどれほど信頼できないかは言うまでもありません (したがって、ブラウザベースの制御は信頼できません)。純粋に実装の観点から、この MAX_FILE_SIZE がどのように機能するかをゆっくり紹介します。 out ファイルの説明 (「Laruence の個人紹介」)、アップロードをクリックした後はどうなりますか?
フォーム送信
ユーザーが送信を確認した後、ブラウザは、action 属性で指定されたページに次のような形式のデータ パケットを送信します。フォーム内 (この場合は、upload.php):
コードは次のとおりです コードをコピー | |
//リクエストヘッダーPOST /upload.php HTTP/1.0rn ... Host : www.laruence .comrn ... Content-length: xxxxxrn ... Content-type: multipart/form-data、boundary=--------------7d51863950254rn 。 ..rnrn //POST データコンテンツの開始 --------------7d51863950254 content-disposition: form-data name="description" larence の自己紹介 ---- --- --------7d51863950254 content-disposition: form-data; name="userfile"; filename="laruence.txt" Content-Type: text/plain ... ラルエンスのコンテンツ.txt.. . ---------------7d51863950254
|
次のステップは、サーバーがこのデータをどのように処理するかです。
アップロードを受け入れます
Web サーバー (ここでは Apache であると仮定します) (PHP がモジュール モードで Apache にインストールされていると仮定します) がユーザーのデータを受信すると、最初に決定します。 HTTP リクエスト ヘッダーに基づいて MIME TYPE を PHP タイプとして設定し、いくつかのプロセスを経た後 (この部分については、以前の PHP ライフ サイクルのページを参照してください)、最終的に制御を PHP モジュールに渡します。
これでこのプロセスでは、PHP は sapi_activate を呼び出してリクエストのタイプ (この時点では POST) を決定し、次に、sapi_read_post_data を呼び出して、rfc1867 処理関数 rfc1867_post_handler を呼び出します。 POST を分析するためのデータが来ます。
rfc1867_post_handler のソース コードは、mian/rfc1867.c にあります。また、ソース コードもリストされています。
その後、PHP は境界を介して、セグメントごとに、それらが同時に定義されているかどうかをチェックします: 名前とファイル名の属性 (名前付きファイルのアップロード) 名前は定義されていません、ファイル名は定義されています (名前なしのアップロード)
名前は定義されている、ファイル名が定義されていない (通常のデータ) ),
別の処理を実行します。 コードは次のとおりです | コードをコピー |
if ((cd = php_mime_get_hdr_value(header, "Content-Disposition "))) { char *pair=NULL; int end=0;
while (isspace(*cd)) { ++cd; }
while (*cd && (pair = php_ap_getword(&cd, ';'))) { char *key =NULL, *word = ペア;
while (isspace(*cd)) { ++cd; }
if (strchr(pair, '=') ) { key = php_ap_getword(&pair, '=' ); F if (! Strcasecmp (key, "name") { // 名前フィールドを取得します iF (Param) { EFREE (Param); } else if ( !strcasecmp(key, "ファイル名")) { (key) { efree(key); } efree(word); }
このプロセスでは、PHP がチェックします。あるかどうか通常のデータの MAX_FILE_SIZE
コードは次のとおりです コードをコピー |
/* 通常形式の変数、すべてのデータをメモリに安全に読み込むことができます */
if (!filename && param) { unsigned int value_len;
char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC); unsigned / (value); continue;} |
|
「はい」の場合、その値に従ってファイル サイズを超えているかどうかを確認します
コードは次のとおりです | コードをコピーします |
if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize) ) { cancel_upload = UPLOAD_ERROR_A; } else if (max_file_size && (total_bytes > max_file_size)) { #if DEBUG_FILE_UPLOAD sapi_module.sapi_error(E_NOTICE, "ファイルの MAX_FILE_SIZE %ld バイトを超えました - [%s = %s] 保存されていません", max_file_size, param, filename); #endif cancel_upload = UPLOAD_ERROR_B; }
|
上記のコードを通して、判定が 2 つの部分に分かれていることもわかります。 、最初の部分は、PHP のデフォルトのアップロード制限を確認することです。2 番目の部分は、ユーザー定義の MAX_FILE_SIZE を確認することです。したがって、フォームで定義されている MAX_FILE_SIZE は、PHP で設定されている最大アップロード ファイル サイズを超えることはできません。
名前とファイル名を判断することで、ファイルアップロードの場合、PHPの設定に従ってファイルアップロードディレクトリにランダムな名前の一時ファイルを作成します:
コードは次のとおりです | コードをコピーします |
if (! Skip_upload) { /* ハンドル ファイル */ fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC); if (fd==-1) { sapi_module.sapi_error(E_WARNING, "ファイルのアップロード エラー - 一時ファイルを作成できません") ; Cancel_upload = UPLOAD_ERROR_E; } }
|
ファイル ハンドルと一時的なランダム ファイル名を返します。
その後、ファイル名が正当である、名前が正当であるなどの検証。
これらの検証に合格した場合は、内容を読み取り、この一時ファイルに書き込みます。
...
コードは次のとおりです | コードをコピーします |
else if (blen > 0) { wlen = write(fd, buff, blen) //一時ファイルを書き込みます if (wlen == -1) { /* 書き込みに失敗しました */ #if DEBUG_FILE_UPLOAD sapi_module.sapi_error(E_NOTICE, "write( ) failed - %s", strerror(errno)); #endif cancel_upload = UPLOAD_ERROR_F; } } ... .
|
ループ読み込みが完了したら、一時ファイルハンドルを閉じます。 レコード一時変数名:
コードは以下の通りです | コードをコピー |
zend_hash_add(SG( rfc1867_uploaded_files) , temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), N ULL);
|
このとき、名前を付けてアップロードするとFILE変数が生成されます。設定します:
コードは次のとおりです | コードをコピーします | $_FILES['userfile'] //name="userfile " |
名前なしのアップロードの場合は、tmp_name を使用して設定します:
コードは次のとおりです | コードをコピーします | $_FILES['tmp_name'] //無名アップロード | 最後にupload.phpの処理をユーザーに渡します。
この時点でupload.phpでは、ユーザーはmove_uploaded_fileで生成したばかりのファイルを操作することができます
|
http://www.bkjia.com/PHPjc/444674.htmlwww.bkjia.com本当http://www.bkjia.com/PHPjc/444674.html技術記事 PHP ファイルアップロードのソースコード解析 (RFC1867) 知っておく必要がある友人はそれを参照できます。HTTP ベースのアップロードは、FTP よりも比較的使いやすく、安全に適用できます。