Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум Apache

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Python Apache CGI upload file
 
 автор: nskrypnik   (19.09.2009 в 21:13)   письмо автору
 
 

Добрый день, я программист, не очень силен в апаче, собственно говоря этого от меня не требовалось. Пока вот не столкнулся с проблемой. Надо было сделать заливку файла через CGI скрипт под апачем. Сделал обычную форму, написал простенький обработчик. Все вроде правильно, но файл заливался не полностью, а только часть файла - от четверти до половины, причем даже когда элементарный файл гружу 86 байт(!), приходит только 52. Начал разбираться - в запросе браузера все нормально - файл целый. Скрипту в stdin приходит уже файл битый. Т.е. проблема в апаче. Тут уже вопрос знатокам - что может быть не так и куда копать?

Апач стоит под WinXP, пробывал версии 2.2.11 и 2.2.13 - одинаковая ерунда.

  Ответить  
 
 автор: heed   (19.09.2009 в 23:32)   письмо автору
 
   для: nskrypnik   (19.09.2009 в 21:13)
 

незнаю как там в Pyton, но браузер отправляет например такой запрос при отправке мелкого текстового файла
POST /PERL/test_UPLOAD.pl HTTP/1.1
User-Agent: Opera/9.22 (Windows NT 5.1; U; ru)
Host: src
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
Connection: Keep-Alive, TE
TE: deflate, gzip, chunked, identity, trailers
Content-Length: 409
Content-Type: multipart/form-data; boundary=----------k37XzkMiLnoUT0ZP00kwdo

------------k37XzkMiLnoUT0ZP00kwdo
Content-Disposition: form-data; name="MAX_FILE_SIZE"

30000
------------k37XzkMiLnoUT0ZP00kwdo
Content-Disposition: form-data; name="userfile"; filename="test.txt"
Content-Type: text/plain

test test test test test test test test test
test test test test test test test test test
test test test test test test test test test
------------k37XzkMiLnoUT0ZP00kwdo--

из такой формы
<form enctype="multipart/form-data" action="http://src/PERL/test_UPLOAD.pl" method="post">
 <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
 Отправить этот файл: <input name="userfile" type="file" />
 <input type="submit" value="Send File" />
</form>

А Apache запускает CGI-обработчили просто передавая post-данные как стандартный ввод
например таким скриптом
#!C:/Perl/bin/perl.exe -w
#<?perl
print "Content-type:text/plain\n\n";

foreach 
my $var (sort keys %ENV) { # просмотр переменных окружения
    
print $var "\t=\t" $ENV{$var} . "\n";
}

print 
"\n\n\t\t---\n";

if  (
$ENV{'CONTENT_LENGTH'}){  # чтение STDIN
 
my $buffer ''
 
binmode STDIN;
 
read(STDIN$buffer$ENV{'CONTENT_LENGTH'});
 print 
$buffer# с бинарным файлом вывод не всегда получится
}

будет получена такая распечатка сначала переменных окружения, а потом того что полученно из STDIN
COMSPEC    =    C:\WINDOWS\system32\cmd.exe
CONTENT_LENGTH    =    409
CONTENT_TYPE    =    multipart/form-data; boundary=----------wY7Khdy9o1O52CvjuVLbRo
DOCUMENT_ROOT    =    C:/X_DOCS/src
.................. Здесь немного сократил..............................
SERVER_SOFTWARE    =    Apache/2.2.11 (Win32) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8i PHP/5.2.11-dev
SYSTEMROOT    =    C:\WINDOWS
WINDIR    =    C:\WINDOWS


        ---
------------wY7Khdy9o1O52CvjuVLbRo

Content-Disposition: form-data; name="MAX_FILE_SIZE"



30000

------------wY7Khdy9o1O52CvjuVLbRo

Content-Disposition: form-data; name="userfile"; filename="test.txt"

Content-Type: text/plain



test test test test test test test test test

test test test test test test test test test

test test test test test test test test test

------------wY7Khdy9o1O52CvjuVLbRo--


Думаю что Вы просто неправильно разбираете то читается из STDIN
, или я не знаю есть-ли вшитые в Pyton функции разбирающие STDIN

  Ответить  
 
 автор: nskrypnik   (20.09.2009 в 11:43)   письмо автору
 
   для: heed   (19.09.2009 в 23:32)
 

Разумеется в python есть модуль CGI, разбирающий и stdin и переменные среды. Плюс я так же выводил stdin, как я говорил выше и воочию видел, что данные теряются. Правда я эксперементировал с картинками, только что попробовал текстовый файл - все передалось нормально.

Может в бинарных данных символ есть какой-то, который не нравится апачу или он его принимает за какой-то знак?

  Ответить  
 
 автор: Trianon   (20.09.2009 в 14:08)   письмо автору
 
   для: nskrypnik   (20.09.2009 в 11:43)
 

можно же сравнить эти два файла (86 и 52 байта)
А вообще неполохо было бы поглядеть сырой поток данных запроса.

  Ответить  
 
 автор: nskrypnik   (20.09.2009 в 16:13)   письмо автору
 
   для: Trianon   (20.09.2009 в 14:08)
 

Вот запрос отловленный LiveHTTPheaders

http://localhost:8080/ezoloto/uploader.py

POST /ezoloto/uploader.py HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; uk; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: uk,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost:8080/ezoloto/?opt=manage&addnew=1&catId=84
Cookie: sid=5b2a296273a7699b3835a360e393b560f4e b8a16; sk_your_site=20090916211847-003f9172703d8eed8d0f7e18fe8257e2; virtuemart=mqcao6d2i2h0os3co4oeioagu7; 4877db55482b87a0f08ee84fe6e3e6ad=-; clickedFolderFrameless=; clickedFoldercheckboxTree=; d541b16baa4b2002091e84ca9bed5da2=gqove9440f8abi9s0j7hbt9nc1; 87356eef8b63a9eda98f3f384caac2ee=baa2428d2a28dca66a5b715d0148dc16; s=1
Content-Type: multipart/form-data; boundary=---------------------------207831803532226
Content-Length: 381
-----------------------------207831803532226
Content-Disposition: form-data; name="upThumbImg"

1
-----------------------------207831803532226
Content-Disposition: form-data; name="datafile"; filename="cart.gif"
Content-Type: image/gif

GIF89a  Ђ ---яяя!щ ,   -ЊЏ©Лќ ‚QАЁ¦щъЂ-бш)ЫЦЃ_hb¤љќ•И^хTѕO^>чl
‡Ѓ ;
-----------------------------207831803532226--

HTTP/1.x 200 OK
Date: Sun, 20 Sep 2009 12:08:43 GMT
Server: Apache/2.2.13 (Win32) PHP/5.2.9-2
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
----------------------------------------------------------



Вот то, что выдает чтение stdin CGI-скриптом.

-----------------------------207831803532226
Content-Disposition: form-data; name="upThumbImg"

1
-----------------------------207831803532226
Content-Disposition: form-data; name="datafile"; filename="cart.gif"
Content-Type: image/gif

GIF89a  Ђ ---яяя!щ ,   -ЊЏ©Лќ ‚Q

  Ответить  
 
 автор: heed   (20.09.2009 в 17:26)   письмо автору
 
   для: nskrypnik   (20.09.2009 в 16:13)
 

в том что здесь смоглось напечататься нет \x00 :)

мне кажется Content-Length: 381 на что нужно ориентироваться читая stdin , и проверяя длинну полученных данных

открыл справку по случайно однажды установленному у меня pyton :) , а там такой пример чтения файла с использованием import cgitb
#<?pyton
fileitem 
form["userfile"]
if 
fileitem.file:
    
# It's an uploaded file; count lines
    
linecount 0
    
while 1:
        
line fileitem.file.readline()
        if 
not line: break
        
linecount linecount 1

что-то мне не нравится это fileitem.file.readline() , должен быть способ считать столько данных сколько нужно в байтах
или должно быть что-то из другого модуля
#<?pyton
import cgi
form 
cgi.FieldStorage()
user form.getfirst("user""").upper()    # This way it's safe.
for item in form.getlist("item"):
    
do_something(item)


Думаю и файл и stdin должны открываться с буквой b во втором параметре open или подобных функций
, насчёт переключения режима уже после открытия дескрипторов не смог найти

  Ответить  
 
 автор: nskrypnik   (20.09.2009 в 19:19)   письмо автору
86 байт
 
   для: heed   (20.09.2009 в 17:26)
 

[quote=heed]в том что здесь смоглось напечататься нет \x00 :)[/quote]
Угу, сейчас Вам напечатается знак терминала в форуме =). В аттаче находится тот самый гиф, можете глянуть его в хексе.

fileitem.file.readline() - только для текстовых файлов катит. Файл у меня открывается с буквой b, а насчет stdin - это уже надо смотреть реализацию cgi.FieldStorage(), но тем не мене когда апач запускается на линуксе - все работает нормально. Проблема только под вин. В общем так и не разобрался.

  Ответить  
 
 автор: .......   (20.09.2009 в 14:15)
 
   для: nskrypnik   (20.09.2009 в 11:43)
 

обычно такое бывает когда строковым функциям попадается в строках NULL (\x00)
, должны использоваться только бинарно-безопасные функции
Возможно проблема в том как идёт запись в файл, или как считывается в переменную то что возвращено CGI-модулем
, самим модулям тоже не всегда бывает вполное можно доверять :)
совсем не зная Pyton ничего не могу сказать

  Ответить  
 
 автор: nskrypnik   (20.09.2009 в 16:17)   письмо автору
 
   для: .......   (20.09.2009 в 14:15)
 

Согласен, но допустим в примере выше NULL присутствует даже в том, что уже передалось.
Пайтон думаю совсем не обязательно знать - проблема в том, что апач передает в stdin скрипту, я не проверял другие языки, но мне кажется возникла бы аналогичная ошибка.

И еще: такая проблема только под win32. В линуксе все работает отлично.

  Ответить  
 
 автор: heed   (20.09.2009 в 20:50)   письмо автору
 
   для: nskrypnik   (20.09.2009 в 16:17)
 

у меня сохраняются точные копии (win32 Apache2.2.11)

только скрипт кривоватый :)
#!c:\Pyton\python.exe
#<?Python v2.6.2
import sys
sys
.stderr sys.stdout
import cgi

print "Content-Type: text/html; charset=cp1251"     # HTML is following
print                               # blank line, end of headers
print "hellofworld"
print '<form enctype="multipart/form-data" action="" method="post">'
print '<input type="hidden" name="MAX_FILE_SIZE" value="30000" />'
print ' : <input name="userfile" type="file" />'
print '<input type="submit" value="Send File" />'
print '</form>'

form cgi.FieldStorage()
if 
not (form.has_key("userfile") and form.has_key("MAX_FILE_SIZE")):
    print 
"<H1>Empty</H1>"
print "<p>MAX_FILE_SIZE:"form["MAX_FILE_SIZE"].value
fileitem 
form["userfile"]

with open('test.bin''wb') as file:
    
file.write(fileitem.value)
print 
fileitem

  Ответить  
 
 автор: nskrypnik   (20.09.2009 в 22:15)   письмо автору
 
   для: heed   (20.09.2009 в 20:50)
 

Везет Вам =). Этот же пример у меня не работает. Единственное, что у меня версия питона 2.5. Короче голова уже кругом идкт %)

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования