Perl-要求によりHTTPサーバーにファイルを送信します

実際、オリジナルではなく、ドキュメンテーションだけで十分です。ただし、後者は非常に強い苦痛を引き起こします。 したがって、レーキを10回読んで踏むよりも、実際にどのように、何をしているのかを実際に示す方が簡単です。 条件:ローカルにあるいくつかのバイナリファイルがあり、これらのファイルを配置する必要があるサーバーがあります。このサーバーには、ファイルをアップロードするスクリプト(フォームハンドラー)があります。

タスク:これらのファイルは、Webインターフェイス(フォームハンドラー)を介してサーバーに追加する必要があります。これは、私たちがブラウザーであり、フォームを介してデータを送信したかのようです。

LWPの使用:: UserAgent

クエリ生成アルゴリズム:

XML :: LibXMLのように退屈ですが、信頼性が高いため、Perlコード(1)
 #!/ usr / bin / perl

厳格な使用;
警告を使用します。
 LWPを使用:: UserAgent;

 #これは送信するファイルです
私の$ file = './files/some_file.bin';
 #これはリクエストを送信するURIです
私の$ uri = 'http://somedomain.com/form/action/script';

 #リクエストオブジェクト
私の$ request = HTTP :: Request-> new( 'POST'、$ uri);

 #セパレータを作成します。強制しない場合、$ ua-> request($ request)でメインヘッダーに移動しません
 #ただし、ヘッダーオブジェクトの形成後に$ request-> as_stringを作成するだけで、デフォルトで置換されますが、リスクはありません
私の$境界= 'X';
 my @rand =( 'a' .. 'z'、 'A' .. 'Z');
 for(0..14){$ boundary。= $ rand [rand(@rand)];}

 #見出しを作成します:
 $ request-> header( 'Content-Type' => 'multipart / form-data; boundary ='。$ boundary);
 $ request-> header( 'User-Agent' => '<i> Mozilla Firefox 5.0 :-) </ i>');
 $ request-> header( 'Referer' => '<i> http://somedomain.com/form </ i>');
 $ request-> protocol( 'HTTP / 1.0');  #LWP :: UserAgentがこれを行いますが、すぐに改善される

 #通常のテキスト形式のパラメーターの形成
 my $ field = HTTP :: Message-> new(
                                 [
                                     'Content-Disposition' => 'フォームデータ;  name = "<i>フィールド名</ i>" '、
                                     'Content-Type' => 'text / plain;  charset = utf-8 '、
                                 ]);  #HTTP :: Headersヘッダーは、HTTP :: Messageオブジェクトの作成中に置換されます
 $ field-> add_content_utf8( '<i> somevalue </ i>');  #どうやら、somevalueはUTF-8である必要があります
 $ request-> add_part($フィールド);
 #...など、各テキストフィールドについて...

 #バイナリフォームパラメーターの形成
オープン(私の$ fh、 '<'、$ファイル);
 #そして、最初にヘッダーを作成し、それをHTTP :: Messageに適用できます
     my $ size =(stat $ file)[7];
     my $ header = HTTP :: Headers-> new;
     $ header-> header( 'Content-Disposition' => 'form-data; name = "<i> file </ i>"; filename = "<i> somefile.bin </ i>');#ただしfilenameファイル名から計算できます
     $ header-> header( 'Content-Type' => '<i> application / octet-stream </ i>');  #またはファイルの種類に適した
     my $ file_content = HTTP :: Message-> new($ header);
     $ file_content-> add_content($ _)while <$ fh>;
     $ request-> add_part($ file_content);
 $ fhを閉じます。
 #...など、各ファイルについて...

私の$ response = $ ua-> request($ request);
 if($ response-> is_success){
    印刷$応答->コンテンツ
 } else {
     die $ response-> status_line
 } 

ソケットを使用する

すべては問題ありませんが、転送用の大きなファイルがある場合、リクエストを収集するためにメモリに完全にアップロードすることは最良の見込みではありません。 したがって、ソケットストリームを介してリクエストを送信することが可能です:Perlコード(2)
 #!/ usr / bin / perl

厳格な使用;
警告を使用します。
 HTTP ::ヘッダーを使用します。
 HTTP ::メッセージを使用します。
 HTTP ::要求を使用します。
 HTTPを使用::応答;
 IOを使用する::ソケット:: INET;

 #これは送信するファイルです
私の$ file = './files/some_file.bin';
 #これはリクエストを送信するURIです
私の$ uri = 'http://somedomain.com/form/action/script';
 #ソケットを使用するため、ドメイン、ポート、およびパスが個別に必要です
 my($ドメイン、$ポート、$パス)= $ uri =〜m / ^(?:https?\:\ / \ /)?([^ \ / \:] +)(?:\:(\ d + ))?(。+)$ /;
 $ポート|| = 80;  #デフォルト
    
 #自転車はもちろん良いですが、既成のモジュールを使用して簡単にヘッダーと非バイナリのリクエスト本文を作成できます
 my $ header = HTTP :: Headers-> new;  $ header-> header( 'Content-Type' => 'multipart / form-data');
私の$ request = HTTP :: Request-> new( 'POST'、$ uri、$ header);  #$パスの代わりに、$ uriがあるので、;-)
 $ request-> protocol( 'HTTP / 1.0');  #プロトコルがデフォルトでHTTP :: Requestを設定しないのは奇妙なので、自分で設定します

 #テキストフィールドなどの少量のデータの場合、自転車も冗長になります
 #(SFCI)条件は前のコード(1)と同じです
 my $ field = HTTP :: Message-> new(
                                 [
                                     'Content-Disposition' => 'フォームデータ;  name = "<i>フィールド名</ i>" '、
                                     'Content-Type' => 'text / plain;  charset = utf-8 '、
                                 ]);
 $ field-> add_content_utf8( '<i> somevalue </ i>');  #そしてここもutf8
 $ request-> add_part($フィールド);
 #...など、各テキストフィールドについて...

 #さらに、リクエストはありますが、ファイルはありませんが、メインヘッダーとコンテンツの最初の部分に分かれています
 #$ request-> headers-> as_stringの正規表現を分割して、リクエストの最初の行、つまりPOSTコマンドを返しません。
 #もちろん、文字列は自分で収集できますが、怠butです。
 my($ head、$ content)= $ request-> as_string =〜m / ^(。+?)\ n \ n(。+)$ / s;
 #コンテンツは完成していないため、切り捨てます-[LF] [EOF]
 $ content = substr($ content、0、-4);
 #同様に境界
 $ content =〜s /(\-\-[^ \ n] +)$ // s;
私の$境界= $ 1;
 #仮リクエストの長さを読む
私の$長さ=長さ$コンテンツ;

 #これでファイル:
私の$ファイル= [];
 my $ size =(stat $ file)[7];
 my $ f_header = HTTP :: Headers-> new;
 $ f_header-> header( 'Content-Disposition' => 'form-data; name = "<i> file </ i>"; filename = "<i> somefile.bin </ i>');
 $ f_header-> header( 'Content-Type' => '<i> application / octet-stream </ i>');
 $ f_header = $ boundary。 "\ n"。$ f_header-> as_string。 "\ n";
 #リクエストの長さに追加します
 $ length + = length $ f_header;
 $長さ+ = $サイズ;
 #実際には、以下の手順は、多くのファイルがある場合にのみ使用されます。
 #次に、コンテンツの長さを計算する必要があります。コンテンツの長さはメインヘッダーで示されるためです
 push @ {$ files}、{header => $ f_header、file => $ file};
 #...など、各ファイルについて...

 #これで完了です
 $ length + = length $ boundary .'-- ';  #エンドラインも考慮
 #ソケットを開く
 my $ socket = IO :: Socket :: INET-> new($ domain。 ':'。$ port)|| 死ぬ!
 #メインタイトルまでは長い
 $ head。= "\ nContent-Length:"。$ length;
 #ヘッダーとコンテンツの最初の(テキスト)部分をソケットに送信します
 $ socket $ headを印刷します。
 print $ socket "\ n \ n";
 $ socket $コンテンツを印刷します。

 foreach my file(@ {$ files}){
     print $ socket $ file-> {header};
     open(my $ fh、 '<'、$ file-> {file});
     print $ socket $ _ while <$ fh>;
     print $ socket "\ n";
     $ fhを閉じます。
 }

 #ファイルの終わりをソケットに送信
 print $ socket $ boundary .'-- '; 
 #ファイルの終わりをソケットに送信
シャットダウン($ソケット、1);
 #ソケットから応答を取得して解析する
 my $ response = HTTP :: Response-> parse(join( ''、<$ socket>));
 if($ response-> is_success){
    印刷$応答->コンテンツ
 } else {
     die $ response-> status_line
 }
    
よくやった(SFCI)コードで斜体で強調表示されているものはすべて、タスク条件の対応する値で置き換える必要があることに注意してください注:SFCI-コピパスターの馬鹿のための特別な。 コメントはありません。



All Articles