[PHP-users 2340] php3 で10人同時にファイルアップロードすると異常。
KIM
php-users@php.gr.jp
Sat, 29 Sep 2001 14:08:18 +0900
木村@ISTと申します。
既知の問題でしたら、ご容赦ください。
現在、WinNTSv4.0 SP6a+IIS4+php3.0.18-i18n-jaで動作させていますが、
ファイルアップロードを10人くらい同時に実行させると、動きがおかしいです。
以下にソースを抜書きします。
送信処理部
<FORM ID="FRM" METHOD=POST ACTION=edit_msg.php3 NAME=edit_msg ENCTYPE=multipart/form-data onSubmit="return CheckFields();">
氏名<BR>
<INPUT TYPE=TEXT NAME=frmName SIZE=30><BR><BR>
題名<BR>
<INPUT TYPE=TEXT NAME=frmSubject SIZE=40><BR><BR>
画像<BR>
<INPUT TYPE=FILE NAME=frmPict SIZE=50><BR><BR>
<INPUT TYPE=SUBMIT VALUE=送信>
<INPUT TYPE=RESET VALUE=クリア>
</FORM>
受け取り処理部
function funcGetNamePath($messageId, $localFullPath, &$filename, &$path, &$urlpath) {
$filename = GetBaseName($localFullPath);
$name = strval($messageId) . "_0." . GetExtention($localFullPath);
$path = DIR_DATA . "/pict/$name";
$urlpath = "/pict/$name";
}
function funcInsert() {
global $cookUserId
global $frmName, $frmSubject, $frmPict, $frmPict_name;
// 接続
$connection = pg_connect(DB_HOST,"","","",DB_NAME);
// 一意のID生成
$queryMessage = "EXEC GETUNIQID";
$resultMessage = pg_exec($connection, $queryMessage);
$maxMessageId = pg_result($resultMessage, 0 , 0);
$queryMessage = "INSERT INTO msg (message_id,user_id,sender_name,subject) VALUES ";
$queryMessage = "$queryMessage ($maxMessageId,$cookUserId,'$frmName','$frmSubject')";
pg_exec($connection, $queryMessage);
// 一意の格納場所生成
funcGetNamePath($maxMessageId, $frmPict_name, $pictureName, $picturePath, $uriPath);
// 格納
if(copy($frmPict, $picturePath)) {
$queryMessage = "INSERT INTO msg_picture VALUES " .
"($maxMessageId, '$pictureName',"'$uriPath')";
pg_exec($connection, $queryMessage);
}
フォームを使用して、ユーザ名とタイトル、画像ファイルを登録させる処理なのですが、
$frmPict_nameに指定したファイル名が返ってきていて、
実際のサーバ上のファイル名が$frmPictに返ってきます。
$frmPictをcopyするのですが、10人中5,6人がそのうちの1人が
指定したファイルをcopyしているようで、同じファイルを登録したことになってしまいます。
1人や2人でやっている場合には、問題がないので、スクリプトの問題では
無いような気がします。
念のため、php3.0.18のソースを見たのですが、post.cに以下の処理があります。
> [php-3.0.18-i18n-ja]
> --- function/post.c:53 -------
> static void php3_getput(void) {
> #if MODULE_MAGIC_NUMBER > 19961007
> char upload_buffer[BUFSIZ];
> #endif
> size_t bytes=0;
> char *fn;
> FILE *fp;
> int length, cnt;
>
> length = GLOBAL(request_info).content_length;
> if (length > php3_ini.upload_max_filesize) {
> php3_error(E_WARNING, "Max file size of %ld bytes exceeded - temporary file not saved", php3_ini.upload_max_filesize);
> SET_VAR_STRING("PHP_PUT_FILENAME", estrdup("none"));
> return;
> }
> fn = tempnam(php3_ini.upload_tmp_dir, "php");
> fp = fopen(fn, "w");
> if (!fp) {
> php3_error(E_WARNING, "File Upload Error - Unable to open temporary file [%s]", fn);
> return;
> }
> ..
>
このtempnamは、テンポラリのファイル名を生成するだけですので、
fopenに時間がかかる場合、複数セッションに同じテンポラリファイル名を
返す、ってことはないのでしょうか?
ちなみに、php4では、実際に作ってます。
php_open_temporary_file内のphp_do_open_temporary_fileで、
Win32の場合、GetTempFileName(path,pfx,0,opend_path)を呼んでおり、
ファイルが開かれた状態で返ってくるようです。
> [php-4.0.6]
> ----- main\rfc1867.c -----
>
> case 3: /* Handle file */
> loc = memchr(ptr, *boundary, rem);
> u = ptr;
> while (loc) {
> if (!strncmp(loc, boundary, len)
> #if NEW_BOUNDARY_CHECK
> && (loc-2>buf && *(loc-2)=='-' && *(loc-1)=='-') /* ensure boundary is prefixed with -- */
> && (loc-2==buf || *(loc-3)=='\n') /* ensure beginning of line */
> #endif
> ) {
> break;
> }
> u = loc + 1;
> urem = rem - (loc - ptr) - 1;
> loc = memchr(u, *boundary, urem);
> }
> if (!loc) {
> php_error(E_WARNING, "File Upload Error - No Mime boundary found after start of file header");
> SAFE_RETURN;
> }
>
> bytes = 0;
>
> fp = php_open_temporary_file(PG(upload_tmp_dir), "php", &temp_filename);
> if (!fp) {
> php_error(E_WARNING, "File upload error - unable to create a temporary file");
> SAFE_RETURN;
> }
> if ((loc - ptr - 4) > PG(upload_max_filesize)) {
> php_error(E_WARNING, "Max file size of %ld bytes exceeded - file [%s] not saved", PG(upload_max_filesize),namebuf);
> upload_successful = 0;
> } else if (max_file_size && ((loc - ptr - 4) > max_file_size)) {
> php_error(E_WARNING, "Max file size exceeded - file [%s] not saved", namebuf);
> upload_successful = 0;
> } else if ((loc - ptr - 4) <= 0) {
> upload_successful = 0;
>
> } else {
> bytes = fwrite(ptr, 1, loc - ptr - 4, fp);
> if (bytes < (loc - ptr - 4)) {
> php_error(E_WARNING, "Only %d bytes were written, expected to write %ld", bytes, loc - ptr - 4);
> }
> upload_successful = 1;
> }
> fclose(fp);
これが原因なのであれば、php4への移行もやむなしかもしれません。
もしくは、tempfile生成処理をphp4に真似て修正するか。。。
良い解決方法がありますでしょうか?お教えください。
*********************************************
木村正人[kim] E-Mail kim@ist.fujitsu.com+
(株)富士通インフォソフトテクノロジ 沼津事業所
private Web http://www.izu.co.jp/~kim/
*********************************************