Запуск внешнего php-скрипта из Delphi - PullRequest
0 голосов
/ 26 мая 2009

Хорошо - это продолжение моего предыдущего вопроса о отправке электронной почты с использованием php-скрипта . Я сейчас использую PEAR для отправки почты. PHP-скрипт, который я использую, следующий (успешный, если выполняется один): PHPEMail.php

<?php
require_once "Mail.php"; // Pear Mail.php 

$from = "FromName <FromName@SomeAddress.com>";
$to = $_POST["destination"]; // destination  
$subject = "Hello You!";
$body = $_POST["nicebody"]; // body of text sent 
$host = "ValidServerName";
$username = "User";         // validation at server    
$password = "Password";     // validation at server 

$headers = array ('From' => $from,
  'To' => $to,
  'Subject' => $subject);
$smtp = Mail::factory('smtp',
  array ('host' => $host,
    'auth' => true,
    'username' => $username,
    'password' => $password));

$mail = $smtp->send($to, $headers, $body);

if (PEAR::isError($mail)) {
  echo("<p>" . $mail->getMessage() . "</p>");
 } else {
  echo("<p>Message successfully sent!</p>");
 }
?>

Теперь мне нужно выполнить этот скрипт (PHPEMail.php) из Delphi, передавая некоторые переменные, используя winsock. Я собираюсь с этим кодом - который не был успешным до сих пор:

Procedure SendEmail;
var
  WSADat:WSAData;
  SomeText:TextFile;
  Client:TSocket;
  Info,TheData,Lina,Nicebody:String;
  SockAddrIn:SockAddr_In;
begin
  try
    if not FileExists(Log) then exit;     
    AssignFile(SomeText, Log);             // try to open log, assigned to SomeText
    Reset(SomeText);                       // Reopen SomeText for reading
    while not Eof(SomeText) do
    begin
      ReadLn(SomeText, Lina);             //read each line of SomeTextans place it in linha
      nicebody:=Nicebody+#13#10+Lina;     // nicebody = all line red from SomeText
    end;
    CloseFile(SomeText);                  // SomeText is closed
    DeleteFile(PChar(Log));               // log is deleted
//
    WSAStartUp(257,WSADat);
    Client:=Socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
    SockAddrIn.sin_family:=AF_INET;
    SockAddrIn.sin_port:=htons(80);
    SockAddrIn.sin_addr.S_addr:=inet_addr('66.66.66.66'); // server IP
    if Connect(Client,SockAddrIn,SizeOf(SockAddrIn))=0 then begin
      Info:='destination='+EmailDestAddressFromIni + '' +'Nicebody='+Nicebody;
      TheData:='POST PHPEMail.php HTTP/1.0'                   +#13#10+
             'Connection: close'                              +#13#10+
             'Content-Type: application/x-www-form-urlencoded'+#13#10+
             'Content-Length: '+IntToStr(Length(Info))       +#13#10+
             'Host: someEmailHostAddress'                         +#13#10+
             'Accept: text/html'                              +#13#10+#13#10+
              Info                                            +#13#10;
      Send(Client,Pointer(TheData)^,Length(TheData),0);
      end;
    CloseSocket(Client);
  except
    exit;
  end;
end;

[... more code not related]

Я почти уверен, что ошибка в «TheData», которая отправляется на веб-сервер. Скрипт PHP просто не запускается. У кого-нибудь есть идея, что идет не так?

(примечание: я хочу использовать winsock, я не хочу сторонних компонентов. Полный код, который представляет собой сервер, весит около 12ko и предназначен для встраивания в какое-то оборудование).

СМ. ФИНАЛЬНЫЙ КОД В КОНЦЕ.


Поскольку я не мог видеть POST в журнале сервера, я сделал некоторые улучшения в своем коде (плюс несколько сообщений об ошибках). ТЕПЕРЬ журнал сервера показывает некоторую трассировку отправленных пакетов ... то есть, обычный идентификатор и время плюс буква "P" ... вероятно, первая буква слова 'POST' (отправленные данные). Таким образом, я должен исследовать команду «Send ()». (Я на Delphi 2009). Я не получаю сообщение об ошибке от winsock или команды send.

Procedure SendEmail;

const
  a = #13#10;

var
  WSAData:TWSAData;
  Texto:TextFile;
  ClientSocket :TSocket;
  Info,Data,Lina,Contenu:String;
  host:SockAddr_In;
  i_result:Integer;

begin
  try
    if not FileExists(Log) then exit;     
    AssignFile(Texto, Log);      
    Reset(Texto);  // Reopen texto for reading
    while not Eof(Texto) do
    begin
      ReadLn(Texto, Lina); //read each line of texto and place it in lina
      Contenu:=Contenu+#13#10+Lina;  // contenu is all lines of texto
    end;
    CloseFile(Texto); // close texto
    DeleteFile(PChar(Log)); // delete log


    // Initialize Winsock
    i_result := WSAStartUp(257,WSAData);
    if (i_Result <> NO_ERROR) then
    begin
     MessageBox(0,'Initialization of winsock failed.','Error',MB_OK Or MB_ICONERROR);
     Exit;
    end;

    // Create a SOCKET for connecting to server
    ClientSocket := Socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
    If ClientSocket = INVALID_SOCKET Then
    begin
     MessageBox(0,'ServerSocket creation failed.','Error',MB_OK Or MB_ICONERROR);
     WSACleanUp;
     Exit;
    end;

    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    host.sin_family:=AF_INET;
    host.sin_port:=htons(80);
    host.sin_addr.S_addr:=inet_addr('77.66.66.66');

    // Connect to server.
    i_result:= Connect(ClientSocket,host,SizeOf(host));
    if i_result = SOCKET_ERROR then
    begin
     MessageBox(0,'Failed to connect to remote computer.','Error',MB_OK Or MB_ICONERROR);
     WSACleanUp;
     Exit;
    end
    else
    begin

      Info := 'destination=' + UrlEncode(CFG.Email) + '&' + 'contenu=' + UrlEncode(contenu);
      Data:='POST /pearemail.php HTTP/1.0'                    +#13#10+
             'Connection: close'                              +#13#10+
             'Content-Type: application/x-www-form-urlencoded'+#13#10+
             'Content-Length: '+IntToStr(Length(Info))        +#13#10+
             'Host: mail.tatata.com'                            +#13#10+
             'Accept: text/html'                              +#13#10+#13#10+
              Info+#13#10;

      // Send buffer
       i_result := Send(ClientSocket,Pointer(Data)^,Length(Data),0);
       if (i_result = SOCKET_ERROR) then
       MessageBox(0,'Failed to send to remote computer.','Error',MB_OK Or MB_ICONERROR);
       closesocket(ClientSocket);
       WSACleanup;
       Exit;

    end;
       // shutdown the connection since no more data will be sent
       i_result:= shutdown(ClientSocket, SD_SEND);
       if (i_Result = SOCKET_ERROR) then
       MessageBox(0,'Shutdown failed.','Error',MB_OK Or MB_ICONERROR);
       closesocket(ClientSocket);
       WSACleanup();
       Exit;

  except
    exit;
  end;
end;

скрипт pearemail.php, ожидающий POST:

<?php
require_once "Mail.php";

$from = "name <name@tatata.com>";
$to = $_POST["destination"];
$subject = "Number 2!";
$body = $_POST["contenu"];
$host = "mail.server.com";
$username = "user";
$password = "password";

$headers = array ('From' => $from,
  'To' => $to,
  'Subject' => $subject);
$smtp = Mail::factory('smtp',
  array ('host' => $host,
    'auth' => true,
    'username' => $username,
    'password' => $password));

$mail = $smtp->send($to, $headers, $body);

if (PEAR::isError($mail)) {
  echo("<p>" . $mail->getMessage() . "</p>");
 } else {
  echo("<p>Message successfully sent!</p>");
 }
?>

Ответы [ 2 ]

2 голосов
/ 26 мая 2009

Как я вижу из вашего кода Delphi, вся информация в электронном письме была упакована в одну переменную, но как в вашем php-скрипте передать ее вашим многочисленным переменным php? Вы должны распаковать / разобрать его, чтобы передать каждую переменную (целевой адрес, тему, почтовое тело и т. Д.) В ваш php-скрипт. (В вашем текущем php-скрипте много $ _posts, но он получает только 1 реальный пост из кода Delphi.)

Ниже приведен мой рабочий код для php-скрипта.

result := 'POST /index.php HTTP/1.1' +
a + 'Host: somehost.com' +
a + 'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080406 K-Meleon/1.1.5' +
a + 'Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5' +
a + 'Accept-Language: en-us,en;q=0.5' +
a + 'Accept-Encoding: gzip,deflate' +
a + 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7' +
a + 'Keep-Alive: 300' +
a + 'Connection: keep-alive' +
a + 'Referer: http://somehost.com/index.php' +
a + 'Content-Type: application/x-www-form-urlencoded' +
a + 'Content-Length: 73' + a +
a + 'link=' + MyHttpEnCodedStrData  + a + a;

а это # ​​13 # 10.

Другая важная вещь - это "link ="; это имя переменной в моем php-скрипте, которая получает / хранит данные, которые я отправляю. Так как я отправляю только 1 переменную, и это не скрипт электронной почты, нет php нужен разбор, поэтому я не вставил сюда свой php-код.

Надеюсь, я дал понять:)

2 голосов
/ 26 мая 2009

Второй токен первой строки HTTP должен быть абсолютным путем URL. Нужно начинать с косой черты.

POST /PHPEMail.php HTTP/1.0

Вам также следует приложить некоторые усилия, чтобы гарантировать, что отправляемые вами данные действительно имеют URL-кодировку, как это говорит тип контента. Символы 10 и 13 не являются допустимыми символами в URL. Вам также необходимо учитывать все символы в текстовом файле, который вы читаете:

Info := 'destination=' + UrlEncode(EmailDestAddressFromIni) +
  '&' + 'Nicebody=' + UrlEncode(Nicebody);

Я заметил, что вы не читаете ответ от сервера. Не игнорируй это. Иногда это может сказать вам, что не так. Я также не видел упоминаний о том, что, по словам журналов сервера, происходило, когда вы пытались запустить свой код.

Вы должны совершать больше подобных ошибок по пути. Подумайте об использовании библиотеки, которая обрабатывает такие вещи для вас, например, Indy , ICS или Synapse . Не переустанавливайте HTTP, если вам действительно не нужно. А если вам действительно не нужен сторонний код, подумайте о стороннем коде (или это сторонний код), используя встроенный в Windows материал. KB 165298 имеет короткий пример использования InternetConnect, HttpOpenRequest и HttpSendRequest для публикации URL-кодированной Форма запроса.

...