Running external PHP script from Delphi

Ok - this is a follow up from my previous question about sending email using a php script . I am now using PEAR to send mail. Using the php script I am as follows: (successful if executed separately): 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>");
 }
?>

      

Now I need to execute this script (PHPEMail.php) from Delphi passing some variables using winsock. I am going with this code that has failed so far:

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]

      

I'm pretty sure the error is in "TheData" that is being sent to the web server. The PHP script just won't run. Anyone have an idea what is going wrong?

(note: I want to use winsock, I don't want third party components. The complete code, which is a server, weighs about 12ko and is meant to be embedded in some hardware).

SEE END CODE AT THE END.


Since I couldn't see the POST in the server log, I made some improvement in my code (plus some error message). Now the server log shows some trace of the packets sent ... ie normal id and time plus lettre "P" ... probably the first letter of the word "POST" (data sent). So I have to investigate the Send () command. (I'm on Delphi 2009). I am not getting any error from winsock or send command.

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 script is waiting for 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>");
 }
?>

      

0


a source to share


2 answers


The second token of the first HTTP line must be an absolute URL. It must start with a forward slash.

POST /PHPEMail.php HTTP / 1.0

You should also make some effort to ensure that the data you submit is indeed URL-encoded, as the content type says. Characters 10 and 13 are not valid characters in a URL. You also need to consider all the characters in the text file you are reading:



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

      

I noticed that you are not reading the response from the server. Don't ignore this. Sometimes it can tell you what happened. I also didn't see any mention of what happened in the server logs when you tried to run your code.

You should make more mistakes like this along the way. Consider using a library that handles this sort of thing for you, like Indy , ICS , or Synapse . Don't reinstall HTTP if you really need to. And if you don't really need third-party code, consider how to use third-party code (or is it third-party?) Using the stuff built into Windows. KB 165298 contains a short example of how to use InternetConnect

, HttpOpenRequest

and HttpSendRequest

for submitting a form request as a URL.

+2


a source


As I can see from your Delphi code, all the information from the email was packaged into one variable, but in your php script, how do you pass that to your multiple php variables? You need to unpack / parse it to pass each variable (target address, subject, mailbox, etc.) into your PHP script. (Your current PHP script has a lot of $ _posts, but it only gets 1 actual post from Delphi code.)

Below is my working code for the php script.

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;

      



a - # 13 # 10.

One more important thing: "link =" is the name of the variable in my php script that accepts / stores the data I am posting. Since I am only posting one variable and this is not an email script, no php parsing is needed, so I did not paste my php code here.

I hope I made it clear :)

+2


a source







All Articles