Loading ...
Sorry, an error occurred while loading the content.
 

Going Beyond PHP - Interfacing with Other Languages

Expand Messages
  • Hasin Hayder
    *Going Beyond PHP - Interfacing with Other Languages* Introduction Sometimes PHP can t get the job done, or it can get the job done, but not quickly or
    Message 1 of 1 , Apr 9, 2005

      Going Beyond PHP - Interfacing with Other Languages

      Introduction

      Sometimes PHP can't get the job done, or it can get the job done, but not quickly or efficiently enough for the needs of your program. Perhaps you simply need to get the output of another program for manipulation. In any of these situations, you need to perform interprocess communication, which is when you communicate and work with another program (known as a process).

      But before we go on, a disclaimer: Most of the information in this chapter is meant either solely for a UNIX system or solely for a Windows NT system. Interprocess communication (IPC) is not as universal as strings, arrays, and numbers because it deals with other processes, not just PHP. Some examples here will work fine on NT but not on UNIX (such as recipe 13.5), and vice versa. When using interprocess communication, you are not dealing with PHP itself; you are going outside the program, where everything is more dependent on the OS.

      This chapter mainly deals with a concept known as process creation, which is opening a new program to do your work. Whether this is achieved by using backticks to capture output into a variable or by the system and exec commands, process creation is the basis of interprocess communication.

      We also do, however, discuss how to use PHP 4's exciting new features such as more integrated COM support and the integrated Java support.

       Capturing the Output of Another Program

      You want to capture the output of another program, such as the output of the date program or the whereis program.

      Technique

      The simplest solution is to use backticks to capture the output of a program into a variable:

      <?php
      $current_date = `date`;
      ?>

      Or, open a pipe to the program from which you want to capture output:

      <?php
      $pp = popen('date', 'r');
      while ($line = fgets($var, 1024)) {
          $output .= $line;
      }
      pclose($pp);
      ?>

      Comments

      The miracle of backticks is that they provide a convenient and easy way to assign the output of a program to a variable. Perhaps some of you are saying that they are too good to be true. No, that's all there is to it. However, there's one catch: Using backticks takes considerably longer than other related procedures simply because the backticks format the output of the program and place it all in the variable to which the output is being assigned.

      In the second method, we open a pipe to the program. We can then manipulate this pipe as if it were a file, meaning that not only can we get output from the pipe as if it were a file, but we can also send data through the pipe via fputs().

      There is another method of collecting the output of your program with PHP, which is via the exec() function. The exec() function will open a pipe to a program and place all the output of the program into an array of lines (the array to fill is the second argument):

      <?php
      exec('date', $output);
      print implode("\n", $output);
      ?>

      Gotcha

      I want to stress this: Whenever interprocess communication is involved, if you are collecting data from your users and executing it on the shell, always use the EscapeShellCmd() function. The EscapeShellCmd() function escapes all the characters that might cause your system harm.

      Printing the Output of a Program

      You want to send the output of a program directly to standard output without any intermediate steps or extra garbage.

      Technique

      Use the passthru() function, which will print the results of your shell command directly to standard output:

      <?php
      passthru('date');
      ?>

      Comments

      If you simply need to execute a command and display the output to the browser, use the passthru() function, which frees you from worrying about the intermediate steps. (This is similar to fpassthru() and readfile(), which act on files.)

      Gotcha

      I stressed this in the previous recipe, but I will also stress it here: Always use the EscapeShellCmd() function when accepting data from your users. In that way, harmful shell characters are escaped.

      passthru(EscapeShellCmd($submitted_data));

       

       

      Opening a Pipe to Another Program

      You want to open a pipe to a process and read or write data to it.

      Technique

      Use the popen() and pclose() functions as substitutes for fopen() and fclose(). You can then treat the pipe just like a file:

      <?php
      $pp = popen("/usr/sbin/sendmail -t", "w") or die("Cannot Fork Sendmail");
      fputs($pp, "To: sterling@...\r\n");
      fputs($pp, "Reply-to: $senders_email\r\n");
      fputs($pp, "From: $senders_email\r\n");
      fputs($pp, "Subject: The Results of your form\r\n\r\n");
      fputs($pp, "$senders_email sent the following comments:\r\n");
      fputs($pp, $comments);
      pclose($pp) or die("Cannot close pipe to Sendmail");
      ?>

      Comments

      In this example, we open a pipe to the sendmail process, and then print the information we want sendmail to deal with to the pipe handle ($pp). Perl programmers might have noticed that this is a PHP version of the classic way of sending form results by e-mail through Sendmail.

      When working with pipes, all data must be in the format in which the other program wants it, because pipes are relatively low level. For example, we terminate each line in the example with both a carriage return and a newline so that the mail sent is compatible with both DOS- and UNIX-based systems.

      Pipes allow for the two way exchange of data, meaning you can both write to a pipe and then retrieve data from a pipe. This makes them a powerful addition to PHP's set of functions for IPC. Examine the following, which reads the output of a Perl script and prints it to the Web browser:

      <?php
      $pp = popen("./some_perl_script.pl", "r")
         or die("cannot fork");
      while ($line = fgets($pp, 1024)) {
          print $line;
      }
      ?>

       

       

      Working with Sockets

      You want to open a socket to either a local port or a remote server.

      Technique

      Use the fsockopen() function, which opens a socket to the specified server. Subsequently, you send to and retrieve information from that socket via the fgets(), fgetss(), and fputs() functions:

      <?php
      $sp = fsockopen($hostname, $port, &$errno, &$errstr, $timeout);
      if (!$sp) {
          print "$errstr  [$errno]<br>\n";
      } else {
          fputs($fp,"GET / HTTP/1.0\r\n\r\n");
          while ($line = fgets($fp, 1024)) {
              print $line;
          }
      fclose($sp);
      }
      ?>

      Comments

      The fsockopen() function provides a simple API for using sockets. For more information on fsockopen() and some of PHP's more advanced socket features, see Chapter 14, "Communicating with Sockets."

      Working with COM Objects

      You are an ASP programmer, and you want to have the same ability to handle COM objects in PHP that you had in ASP.

      Technique

      With the advent of PHP 4, you can now manipulate COM objects with unparalleled ease:

      <?php
      $word = new COM("word.application")
        or die("Unable to instanciate Word");
      print "Loaded Word, version {$word->Version}\n";
      $word->Visible = 0;
      $word->Documents->Add();
      $word->Selection->TypeText("Testing, testing… 1,2,3");
      $word->Documents[1]->SaveAs("some_tst.doc");
      $word->Quit();
      ?>

      Comments

      For a long time, one of strongest arguments for ASP was the ability for programmers to access prebuilt COM objects from the Web inside the code, meaning that you really didn't need to do that much programming in ASP. You could write the application end of your Web site in C, C++, or Visual Basic, and then interface it to the Web with ASP and COM objects. Now that PHP supports this feature, I don't really see a reason ever to use ASP. PHP is cross-platform, and much easier to work with or learn, if you have programmed in a language such as C, Perl, or Java. Take the following example in PHP, and compare it to the same example in ASP:

      <?php
      require("DB.php");
      $excel_handle = new COM("excel.application");
      $excel_handle->Visible = false;
      $worksheet = $excel_handle->workbooks->add();
      $values = array("Name", "Salary", "Time of Employment");
      for ($i = 1; $i < 4; ++$i) {
          $cell = &$worksheet->Cells(1, $i);
          $cell->value = $values[$i - 1];
       
      $dbh = new DB;
      $dbh->connect("mssql://username:password@localhost/empreports");
      $sth = $dbh->query("SELECT * FROM empnames WHERE salary='salary'");
       
      $idx = 2;
          while ($row = $dbh->fetchRow($sth, DB_GETMODE_ASSOC)) {
          $values = array($row['name'], $row['Salary'], $row['toe']);
          for ($i = 0; $i < 4; ++$i) {
              $cell = &$worksheet->Cells($idx, $i);
              $cell->value = $values[$i - 1];
          }
       
      $dbh->disconnect();
      $worksheet->SaveAs("emp_reports-$salary.xls");
      $excel_handle->quit();
      ?>

      Here is the same example in ASP:

      <%
      Dim excel_handle, worksheet, FileName 'Manipulating the xls file
      Dim dbh, sth, stmt                    'Database related
      Dim i, x                              'For looping and assigning
      Dim Salary                            'From user input
       
      set Salary = request.queryString("salary")
       
      set excel_handle = server.createObject("excel.application") 'COM Object
      excel_handle.visible = False
      excel_handle.workbooks.Add
      set worksheet = excel_handle.Worksheets(1)
       
      ' START DATABASE CONNECTION AND ADD RECORDS
       
      set dbh = server.createObject("ADODB.Connection")
      dbh.Open "DSN=empreports;uid=username;pwd=password"
      set stmt = "SELECT * FROM empnames WHERE salary='"
      stmt = stmt & Salary & "'"
       
      set x=2
      For i=0 to sth.eof
          Worksheet.Cells(x,1) = sth(i).name
          Worksheet.Cells(x,2) = sth(i).salary
          Worksheet.Cells(x++, 3) = sth(i).toe
          sth.movenext
      next
       
      dbh.close
       
      worksheet.SaveAs "emp_reports-" & Salary & ".xls"
      excel_handle.quit
       
      set worksheet = Nothing
      set excel_handle = Nothing
      %>

      Judge for yourself.

      Accessing Predefined Java Methods and Classes

      You want to access methods and classes from Java's set of built-in methods and classes (that is, java.io.lang).

      Technique

      No problem! As of PHP 4, Java support is built in:

      <?php
      $formatter = new Java("java.text.SimpleDateFormat",
                            "EEEE, MMMM dd, yyyy 'at' h:mm:ss a zzzz");
      print $formatter->format(new Java("java.util.date"));
      ?>

      Comments

      Here we create a special object, the Java object. The first argument to the constructor is the class we want to work with (in this case, it is java.text.SimpleDateFormat), and the second argument (as well as the third, fourth, and so on) are the arguments we want to pass to the class specified in the first argument.

      Having the ability to interface with Java is tremendously useful. For example, much of the XML and XSL functionality in the Open Source world is available only through Java classes. The PHP-Java connection enables you to harness this power for your applications. For example, you could generate XML in PHP and then pass it to a Java XSL formatter class to generate HTML.

      Accessing Your Own Custom Java Methods and Classes

      You want to write your components and then call your predefined class.

      Technique

      Create your class, place it in your Java lib file, and then call the class file with the syntax described in recipe 13.6.

      The Java class: SimpleClass

      public class SimpleClass {
          public string get_greeting(string name) {
              return "Hello, there, " + name + ".";
          }
      }

      The PHP script to access SimpleClass:

      <?php
      $jclass = new Java("SimpleClass");
      print $jclass->get_greeting ("Joe");
      ?>

      Comments

      We created our own simple Java class (SimpleClass) with a method (get_greeting), and then called that class from within our PHP program. That is basically how you do it, but remember that your class must be in a special directory where all the predefined classes for the JVM are stored (for me, it is windows\java\trustlib). Consult your Java documentation for more information.

      This is a simple example; nothing is accomplished that we couldn't have accomplished in PHP. So, how is this useful? Assume that we have a mainframe that we need Java to connect to, and we need to connect that mainframe to the Internet. We might be able to use something like a Java applet or Java servlets, but a much simpler solution is to use PHP to connect to Java, which in turn would connect to the mainframe. We are done!

      This is such an important feature that it certainly deserves a more powerful example. Therefore, I wrote the following Java class, Zipper, which zips files into *.zip files that can then be distributed from your Web site. Interfacing with this class enables us to create zip files on-the-fly and give them to our users. (I am not doing tar.gz files because PHP already offers this functionality. See http://www.php.net/manual/html/_ref.zlib.html for more information.)

      First, the Java source file: Zipper.java

      import java.io.*;
      import java.util.zip.*;
       
      public class Zipper {
          public int chunk = 8192;
      public string Zipem ( String files, String zipped ) {
          String this_file = '';
       
          if (files.length() < 1) {
              return "You need to have some files to Zip";
          }
       
          // Output stream
          try {
              FileInputStream foward = new FileInputStream(zipped);
              ZipOutputStream final = new ZipOutputStream(foward);
          } catch (IOException e) {
              return "Cannot create " + zipped + " an error occurred";
          }
       
          do {
             if (files.indexOf("|" != -1) {
                this_file = files.substring(0, files.indexOf("|") );
                try {
                    ZipEntry ent;
                    if (this_file.indexOf("/") != -1) {
                        ent = new ZipEntry(this_file.substring(
                              this_file.lastIndexOf("/") +1,
                              this_file.length())
                             );
                    } else {
                        ent = new ZipEntry(this_file.substring(
                               this_file.lastIndexOf("\\") +1,
                               this_file.length())
                              );
                    }
                    final.putNextEntry(ent);
                } catch (IOException e) {
                    return "Cannot prepare " + zipped +
                           "Unable to add" + this_file;
                }
                files.substring( files.indexOf("|")+1 );
                byte[] buf = new byte[chunk];
       
                //Compress that file
                try {
                    FileInputStream reader = new FileInputStream(this_file);
                 int length;
                 while ((length = reader.read(buf, 0 chunk)) != -1) {
                     final.write(buf, 0, length);
                 }
                 reader.close();
             } catch (IOException e) {
                 return "Can't compress " + this_file;
             }
          }
      } while (files.indexOf("|") != -1);
       
      try {
          ZipEntry ent;
          if (files.indexOf("/") != -1) {
              ent = new ZipEntry(files.substring(
                    files.lastIndexOf("/") + 1,
                    files.length())
                   );
          }  else {
               ent = new ZipEntry(files.substring(
                     files.lastIndexOf("\\") + 1,
                     files.length())
                    );
          }
          final.putNextEntry(ent);
      } catch (IOException e) {
           return "Cannot prepare " + zipped + " unable to add " + this_file;
      }
       
      byte[] buf = new byte[chunk];
       
      try {
          FileInputStream reader = new FileInputStream(files);
          int length;
          while ((length = reader.read(buf,0,chunk)) != -1) {
              final.write(buf,0,length);
          }
          reader.close();
      } catch (IOException e) {
          return "Cannot compress " + files;
      }
       
      try {
                 final.close();
            }  catch (IOException e) {
                 return "Cannot create" + zipped;
            }
       
            return zipped + " has been created";
        }
      }

      Now the PHP script that interfaces with this class:

      <?php
      $zipObj = new Java("Zipper");
      $files = array("/home/designmm/designmultimedia-logs/access_log",
                     "/home/designmm/designmultimedia-logs/error_log");
       
      $ret_val = $zipObj->ZipEm(implode("|", $files), "logs.zip");
      if ($ret_val == "logs.zip has been created") {
          header("http://www.designmultimedia.com/logs/logs.zip");
      } else {
      ?>
      <html>
      <head>
          <title> Sorry there was an error <?php echo $ret_val; ?></title>
      </head>
      <body>
          <h1> I'm Sorry there seems to have been an error </h1>
      <br>
          <b> <?php echo $ret_val; ?> </b>
      <br><br>
        Please try again some other time.
      </body>
      </html>
      <?php
      }
      ?>

       



      --

      Hasin Hayder
      Systech Digital
    Your message has been successfully submitted and would be delivered to recipients shortly.