0

これは私の以前の質問に関連しており、これが私の問題の解決策であると思われるものを見つけましたが、それを機能させることができず、私を助けてくれる人が必要です.

これは、
コード TIdMIMEBoundary.FindBoundary() が宣言されていない識別子であり、Fetch() の問題であるコードです。

uses
...
IdTCPConnection, IdTCPClient, IdHTTP, IdBaseComponent,
  IdComponent, IdCustomTCPServer, IdCustomHTTPServer, IdHTTPServer,
  IdContext, IdMultipartFormData, IdHeaderList, IdMessageCoder,
  IdMessageCoderMIME, IdMessage, IdGlobalProtocols;


procedure DecodeFormData(const Header: String; ASourceStream:TStream);
var
  MsgEnd: Boolean;
  Decoder: TIdMessageDecoder;
  Tmp: String;
  Dest: TStream;
begin
  MsgEnd := False;
  Decoder := TIdMessageDecoderMIME.Create(nil);
  try
    TIdMessageDecoderMIME(Decoder).MIMEBoundary :=
    TIdMIMEBoundary.FindBoundary(Header);
    Decoder.SourceStream := ASourceStream;
    Decoder.FreeSourceStream := False;
    Decoder.ReadLn;
    repeat
      Decoder.ReadHeader;
      case Decoder.PartType of
        mcptUnknown:
        raise Exception.Create('Unknown form data detected');

        mcptText:
        begin
          Tmp := Decoder.Headers.Values['Content-Type'];
          Dest := TMemoryStream.Create;
          try
            Decoder := Decoder.ReadBody(Dest,MsgEnd);
            if AnsiSameText(Fetch(Tmp, ';'),'multipart/mixed') then
              DecodeFormData(Tmp, Dest)
             else
            // use Dest as needed...
          finally
            FreeAndNil(Dest);
          end;//try
        end;

      mcptAttachment:
      begin
        Tmp := ExtractFileName(Decoder.FileName);
        if Tmp <>'' then
          Tmp := 'c:\some folder\' + Tmp
        else
          Tmp := MakeTempFilename('c:\somefolder\');
        Dest := TFileStream.Create(Tmp, fmCreate);
        try
          Decoder := Decoder.ReadBody(Dest,MsgEnd);
        finally
          FreeAndNil(Dest);
        end;//try
      end;

      end;

      until (Decoder = nil) or MsgEnd;
  finally
    FreeAndNil(Decoder);
  end;//try
end;
4

2 に答える 2

1

使用句にIdMessageとIdMessageCoderMIMEを含める必要があります

于 2012-06-29T09:41:26.523 に答える
-2

サーバーで受信したすべてのマルチパート/フォーム データ コンテンツを 1 ステップでデコードする TIdMultiPartFormDataStreamReader というオブジェクトを作成しました。

unit idMultipartFormDataReader;

interface

{$I IdCompilerDefines.inc}

uses System.SysUtils, System.Classes, IdGlobal, IdGlobalProtocols,
  idMultipartFormData, IdCustomHTTPServer,
  IdCoderQuotedPrintable, IdCoderMIME, IdHeaderList;

type
  TIdMultiPartFormDataStreamReader = class( TIdMultiPartFormDataStream )
  private
    FRequestInfo: TIdHTTPRequestInfo;
  protected
    procedure decodeStream;
  public
    property Fields: TIdFormDataFields read FFields;
    constructor Create( ARequestInfo: TIdHTTPRequestInfo );
  end;

implementation

{ TIdMultiPartFormDataStreamReader }

constructor TIdMultiPartFormDataStreamReader.Create(
  ARequestInfo: TIdHTTPRequestInfo);
begin
  inherited Create;
  FSize := 0;
  FInitialized := False;
  FFields := TIdFormDataFields.Create(Self);
  FRequestInfo := ARequestInfo;
  decodeStream;
end;

procedure TIdMultiPartFormDataStreamReader.decodeStream;
var
  delimi, cadStream: string;
  cabeceras: TIdHeaderList;
  stInfo: TMemoryStream;
  posIniPost, posFinPost, posIniRetorno: Integer;
  cadenaOri: string;
  fieldName: string;
  fieldFileName: string;
  contentType: string;
  charSet: string;
  transferEnconding: string;
  {$IFDEF STRING_IS_ANSI}
    LBytes: TIdBytes;
  {$ENDIF}

  function ReadStringLn( StreamOri: TStream; var cadenaBus: string; char_set: string ): Boolean;
  var
    candidato: Boolean;
    posIniSO: Integer;
    posFinSO: Integer;
    StreamDes: TMemoryStream;
    bleer: Byte;
  begin

    candidato := False;
    StreamDes := TMemoryStream.Create;
    posIniSO := StreamOri.Position;

    cadenaBus := '';

    while ( not candidato ) and ( StreamOri.Position < StreamOri.Size ) do begin

      StreamOri.Read( bleer, 1 );

      if ( bleer = 13 ) then begin

        StreamOri.Read( bleer, 1 );

        if ( bleer = 10 ) then  begin

          candidato := True;
          posFinSO := StreamOri.Position;
          StreamOri.Position := posIniSO;

          if ( posFinSO - 2 - posIniSO > 0 ) then begin

            StreamDes.CopyFrom( StreamOri, posFinSO - 2 - posIniSO );

            StreamDes.Position := 0;

            cadenaBus := IdGlobalProtocols.ReadStringAsCharset( StreamDes, char_set );

          end;

          StreamOri.Position := posFinSO;

        end;

      end;

    end;


    StreamDes.Free;
    Result := candidato;

  end;
begin
  {$IFDEF STRING_IS_ANSI}
  LBytes := nil;
  {$ENDIF}

  if ( ExtractHeaderItem( FRequestInfo.RawHeaders.Values[ 'Content-Type' ] ) <> 'multipart/form-data' ) then
    Exit;

  cabeceras := TIdHeaderList.Create( TIdHeaderQuotingType.QuoteHTTP );

  delimi := FRequestInfo.RawHeaders.Params['Content-Type', 'boundary'];

  FBoundary := delimi;

  FRequestContentType := sContentTypeFormData + FBoundary;

  FRequestInfo.PostStream.Position := 0;

  if ( ReadStringLn( FRequestInfo.PostStream, cadenaOri, FRequestInfo.CharSet ) ) then begin

    while ( cadenaOri = '--' + delimi )  and
          ( FRequestInfo.PostStream.Position < FRequestInfo.PostStream.Size ) do begin

      if ( ReadStringLn( FRequestInfo.PostStream, cadenaOri, FRequestInfo.CharSet ) ) then begin

        while ( cadenaOri <> '' ) and
          ( FRequestInfo.PostStream.Position < FRequestInfo.PostStream.Size ) do begin

          cabeceras.Add( cadenaOri );
          ReadStringLn( FRequestInfo.PostStream, cadenaOri, FRequestInfo.CharSet );

        end;

        fieldName := cabeceras.Params[ 'Content-Disposition', 'name' ];
        fieldFileName := cabeceras.Params[ 'Content-Disposition', 'filename' ];


        contentType := ExtractHeaderItem( cabeceras.Values[ 'Content-Type' ] );
        charSet := cabeceras.Params[ 'Content-Type', 'charset' ];

        transferEnconding := cabeceras.Values[ 'Content-Transfer-Encoding' ];

        stInfo := TMemoryStream.Create;
        posIniPost := FRequestInfo.PostStream.Position;
        posFinPost := posIniPost;

        ReadStringLn( FRequestInfo.PostStream, cadenaOri, FRequestInfo.CharSet );

        while ( cadenaOri <> '--' + delimi ) and ( cadenaOri <> '--' + delimi + '--' )  and
          ( FRequestInfo.PostStream.Position < FRequestInfo.PostStream.Size ) do begin

          posFinPost := FRequestInfo.PostStream.Position;
          ReadStringLn( FRequestInfo.PostStream, cadenaOri, FRequestInfo.CharSet );

        end;

        posIniRetorno := FRequestInfo.PostStream.Position;

        FRequestInfo.PostStream.Position := posIniPost;

        if ( posFinPost - 2 - posIniPost > 0 ) then begin

          if ( fieldFileName <> '' ) then begin

            stInfo.CopyFrom( FRequestInfo.PostStream, posFinPost - 2 - posIniPost );

            if ( LowerCase( transferEnconding ) = 'quoted-printable' ) then begin

              stInfo.Position := 0;

              cadStream := ReadStringFromStream( stInfo );

              stInfo.Clear;
              stInfo.Position := 0;

              TIdDecoderQuotedPrintable.DecodeStream( cadStream, stInfo );

            end else if ( LowerCase( transferEnconding ) = 'base64' ) then begin

              stInfo.Position := 0;

              cadStream := ReadStringFromStream( stInfo );

              stInfo.Clear;
              stInfo.Position := 0;

              TIdDecoderMIME.DecodeStream( cadStream, stInfo );

            end;

            stInfo.Position := 0;

            AddFormField( fieldName, contentType, charSet, stInfo, fieldFileName );

          end else begin

            stInfo.CopyFrom( FRequestInfo.PostStream, posFinPost - 2 - posIniPost );

            cadStream := '';

            stInfo.Position := 0;

            {$IFDEF STRING_IS_ANSI}

            ReadTIdBytesFromStream( stInfo, LBytes, stInfo.Size );

            {$ENDIF}

            if ( LowerCase( transferEnconding ) = '7bit' ) then begin

              {$IFDEF STRING_IS_UNICODE}

              cadStream := ReadStringFromStream( stInfo, -1, IndyTextEncoding_ASCII );

              {$ELSE}

              CheckByteEncoding( LBytes, IndyTextEncoding_ASCII, CharsetToEncoding( charSet ) );

              {$ENDIF}

            end else if ( LowerCase( transferEnconding ) = 'quoted-printable' ) then begin

              {$IFDEF STRING_IS_UNICODE}

              cadStream := ReadStringFromStream( stInfo );

              cadStream := TIdDecoderQuotedPrintable.DecodeString( cadStream, CharsetToEncoding( charSet ) );

              {$ELSE}

              BytesToRaw( LBytes, cadStream, Length( LBytes ) );

              LBytes := TIdDecoderQuotedPrintable.DecodeBytes( cadStream );

              {$ENDIF}

            end else if ( LowerCase( transferEnconding ) = 'base64' ) then begin

              {$IFDEF STRING_IS_UNICODE}

              cadStream := ReadStringFromStream( stInfo );

              cadStream := TIdDecoderMIME.DecodeString( cadStream, CharsetToEncoding( charSet ) );

              {$ELSE}

              BytesToRaw( LBytes, cadStream, Length( LBytes ) );

              LBytes := TIdDecoderMIME.DecodeBytes( cadStream );

              {$ENDIF}

            end else if ( LowerCase( transferEnconding ) = '8bit' ) or ( LowerCase( transferEnconding ) = 'binary' ) then begin

              {$IFDEF STRING_IS_UNICODE}

              cadStream := ReadStringAsCharset( stInfo, charSet );

              {$ENDIF}

            end;

            {$IFDEF STRING_IS_ANSI}

            BytesToRaw( LBytes, cadStream, Length( LBytes ) );

            {$ENDIF}

            AddFormField( fieldName, cadStream, charSet, contentType );

            stInfo.Free;

          end;

        end;

        FRequestInfo.PostStream.Position := posIniRetorno;

        cabeceras.Clear;

      end;

    end;

  end;

end;

end.

プロジェクトはhttps://github.com/enriquecerda/TIdMultiPartFormDataStreamReaderにあります

于 2017-01-07T09:20:28.380 に答える