ユーザーが自分のアバターをアップロードしたいときに、「FTP クライアントを開いて、ファイルを http://www.jb51.net/uploads/ にアップロードし、名前を 2dk433423l.jpg にしてください」とは言いませんよね。
HTTP に基づくアップロードは、FTP よりもはるかに使いやすく、安全です。適用できるアップロード方法は、PUT、WEBDAV、および RFC1867 です。この記事では、RFC1867 実装での HTTP ベースのアップロードの使用方法を分析します。ファイルのアップロード
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 の個人紹介」) を入力してアップロードをクリックすると、何が起こりますか?フォーム送信
次のステップは、サーバーがこのデータをどのように処理するかです。
アップロードを受け入れる
を参照してください)、最終的に制御は 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>
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>
名前とファイル名を判断し、ファイルアップロードの場合は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.htmlwww.bkjia.com
true