ホームページ > バックエンド開発 > PHPチュートリアル > PHPファイルアップロードのソースコード解析(RFC1867)_PHPチュートリアル

PHPファイルアップロードのソースコード解析(RFC1867)_PHPチュートリアル

WBOY
リリース: 2016-07-21 15:43:41
オリジナル
930 人が閲覧しました

ユーザーが自分のアバターをアップロードしたいときに、「FTP クライアントを開いて、ファイルを http://www.jb51.net/uploads/ にアップロードし、名前を 2dk433423l.jpg にしてください」とは言いませんよね。

HTTP に基づくアップロードは、FTP よりもはるかに使いやすく、安全です。適用できるアップロード方法は、PUT、WEBDAV、および RFC1867 です。この記事では、RFC1867 実装での HTTP ベースのアップロードの使用方法を分析します。ファイルのアップロード

RFC1867

RCF1867 は HTML 標準プロトコルのフォームベースのファイル アップロードです。RFC1867 標準は HTML に 2 つの変更を加えています:

1 为input元素的type属性增加了一个file选项。<br>2 input标记可以具有accept属性,该属性能够指定可被上传的文件类型或文件格式列表。<br>
ログイン後にコピー


さらに、この規格は新しい MIME タイプ multipart/form-data も定義しており、enctype="multipart/form-data" のファイルを処理するとき、および/または
たとえば、HTML がユーザーに 1 つ以上のファイルをアップロードしてもらいたい場合、次のように書くことができます:

<form enctype="multipart/form-data" action="upload.php" method=post><br>选择文件:<br><input name="userfile" type="file"><br>文件描述:<br><input name="description" type="text"><br><input type="submit" value="上传"><br></form><br>
</p>
<p>このフォームは誰もがよく知っているはずですが、PHP ではデフォルトのフォーム要素 MAX_FILE_SIZE を定義しており、ユーザーはこの非表示のフォーム要素を使用して、PHP がアップロードされるファイルの最大サイズのみを許可することを示唆できます。ユーザーがアップロードするファイルが 5000 (5k) バイトを超えないようにする場合は、次のように記述できます: </p>
<pre class="brush:php;toolbar:false"><form enctype="multipart/form-data" action="upload.php" method=post><br><input type="hidden" value="5000" name="MAX_FILE_SIZE"> <!--文件大小--><br>选择文件:<br><input name="userfile" type="file"><br>文件描述:<br><input name="description" type="text"><br><input type="submit" value="上传"><br></form><br>
ログイン後にコピー

この MAX_FILE_SIZE がいかに信頼できないかは言うまでもありません (したがって、ブラウザベースの制御は信頼できません) 純粋に実装の観点から、この MAX_FILE_SIZE がどのように機能するかをゆっくりと紹介します。

ユーザーがファイル (laruence.txt) を選択し、ファイルの説明 (「Laruence の個人紹介」) を入力してアップロードをクリックすると、何が起こりますか?

フォーム送信

ユーザーが送信を確認した後、ブラウザは、フォーム (この場合は、upload.php) の action 属性で指定されたページに、同様の形式のデータ パケットを送信します。

次のステップは、サーバーがこのデータをどのように処理するかです。

アップロードを受け入れる

ここでは Apache であると仮定します (PHP がモジュールとして Apache にインストールされているとも仮定します) ウェブサーバーがユーザーのデータを受信すると、まず HTTP リクエストヘッダーに基づいて MIME TYPE を PHP タイプとして決定し、次に、いくつかのプロセスを経た後 (この部分については、以前の

PHP ライフ サイクル ppt

を参照してください)、最終的に制御は PHP モジュールに渡されます。 このとき、PHP は sapi_activate を呼び出してリクエストを初期化します。このプロセスでは、まずリクエストのタイプ (この時点では POST) を決定し、次に、Content-type を通じて rfc1867 処理関数 rfc1867_post_handler を見つけます。 POST からのデータを分析するには、このハンドラーを呼び出します。 rfc1867_post_handler のソース コードは mian/rfc1867.c にあります。また、ソース コードのリストも記載されている、PHP ファイルのアップロードに関する以前の詳細な理解を参照することもできます。

その後、PHP は境界を通過し、各セグメントに対してそれも定義されているかどうかをチェックします:

//请求头<br>POST /upload.php HTTP/1.0\r\n<br>...<br>Host: www.laruence.com\r\n<br>...<br>Content-length: xxxxx\r\n<br>...<br>Content-type: multipart/form-data, boundary=--------------7d51863950254\r\n<br>...\r\n\r\n<br>//开始POST数据内容<br>---------------7d51863950254<br>content-disposition: form-data; name="description"<br>laruence的个人介绍<br>---------------7d51863950254<br>content-disposition: form-data; name="userfile"; filename="laruence.txt"<br>Content-Type: text/plain<br>... laruence.txt 的内容...<br>---------------7d51863950254<br>
ログイン後にコピー
処理が異なります。

 name和filename属性(有名文件上传)<br> 没有定义name定义了filename(无名上传)<br> 定义了name没有定义filename(普通数据),<br>
ログイン後にコピー
このプロセスで、PHPは通常のデータにMAX_FILE_SIZEがあるかどうかを確認します。

if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {<br> char *pair=NULL;<br> int end=0;<br><br> while (isspace(*cd)) {<br> ++cd;<br> }<br><br> while (*cd && (pair = php_ap_getword(&cd, ';')))<br> {<br> char *key=NULL, *word = pair;<br><br> while (isspace(*cd)) {<br> ++cd;<br> }<br><br> if (strchr(pair, '=')) {<br> key = php_ap_getword(&pair, '=');<br><br> if (!strcasecmp(key, "name")) {<br> //获取name字段<br> if (param) {<br> efree(param);<br> }<br> param = php_ap_getword_conf(&pair TSRMLS_CC);<br> } else if (!strcasecmp(key, "filename")) {<br> //获取filename字段<br> if (filename) {<br> efree(filename);<br> }<br> filename = php_ap_getword_conf(&pair TSRMLS_CC);<br> }<br> }<br> if (key) {<br> efree(key);<br> }<br> efree(word);<br> }<br>
ログイン後にコピー
「はい」の場合、その値に従ってファイルサイズを超えているかどうかをチェックします。

 /* Normal form variable, safe to read all data into memory */<br>if (!filename && param) {<br> unsigned int value_len;<br> char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);<br> unsigned int new_val_len; /* Dummy variable */<br> ......<br><br> if (!strcasecmp(param, "MAX_FILE_SIZE")) {<br> max_file_size = atol(value);<br> }<br><br> efree(param);<br> efree(value);<br> continue;<br>}<br>
ログイン後にコピー
上記のコードから、判断が 2 つの部分に分かれていることもわかります。最初の部分は PHP のデフォルトのアップロード制限を確認することであり、2 番目の部分はユーザー定義の MAX_FILE_SIZE を確認することです。フォームは PHP で設定された最大アップロード ファイル サイズを超えることはできません。

名前とファイル名を判断し、ファイルアップロードの場合はphp:

if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) {<br> cancel_upload = UPLOAD_ERROR_A;<br>} else if (max_file_size && (total_bytes > max_file_size)) {<br>#if DEBUG_FILE_UPLOAD<br> sapi_module.sapi_error(E_NOTICE,<br> "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved",<br> max_file_size, param, filename);<br>#endif<br> cancel_upload = UPLOAD_ERROR_B;<br>}<br>
ログイン後にコピー
の設定に従ってファイルアップロードディレクトリにランダムな名前の一時ファイルを作成します ファイルハンドルと一時的なランダムなファイル名を返します。

その後、ファイル名が正当であるか、名前が正当であるかなど、いくつかの検証が行われます。

これらの検証に合格した場合は、内容を読み取り、この一時ファイルに書き込みます。

 if (!skip_upload) {<br> /* Handle file */<br> fd = php_open_temporary_fd_ex(PG(upload_tmp_dir),<br> "php", &temp_filename, 1 TSRMLS_CC);<br> if (fd==-1) {<br> sapi_module.sapi_error(E_WARNING,<br> "File upload error - unable to create a temporary file");<br> cancel_upload = UPLOAD_ERROR_E;<br> }<br>}<br>
ログイン後にコピー

ループ読み取りが完了したら、一時ファイルハンドルを閉じて、一時変数名を記録します:

.....<br>else if (blen > 0) {<br> wlen = write(fd, buff, blen); //写入临时文件.<br> if (wlen == -1) {<br> /* write failed */<br>#if DEBUG_FILE_UPLOAD<br> sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));<br>#endif<br> cancel_upload = UPLOAD_ERROR_F;<br> }<br>}<br>....<br>
ログイン後にコピー

そして、FILE 変数を生成します。このとき、有名なアップロードの場合は、次のように設定されます:

zend_hash_add(SG(rfc1867_uploaded_files), temp_filename,<br> strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);<br>
ログイン後にコピー

名前のないアップロードの場合、tmp_name を使用して次の設定が行われます:

$_FILES['userfile'] //name="userfile"<br>
ログイン後にコピー

最終的に、処理のためにユーザーが作成したupload.phpに渡されます。

この時点で、upload.phpでは、ユーザーはmove_uploaded_file~

を通じて生成されたばかりのファイルを操作できます

http://www.bkjia.com/PHPjc/320717.html

www.bkjia.com

tru​​e

技術記事ユーザーがアバターをアップロードしたいときに、「FTP クライアントを開いてファイルを http://www.jb51.net/uploads/ にアップロードし、名前を 2dk433423l.jpg にしてください」とは言わないでしょう? HTTP に基づいて ...
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート