COMPANY

BLOGS

  • user warning: Unknown column 'u.signature_format' in 'field list' query: SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, c.homepage, u.uid, u.name AS registered_name, u.signature, u.signature_format, u.picture, u.data, c.thread, c.status FROM comments c INNER JOIN users u ON c.uid = u.uid WHERE c.nid = 19318 AND c.status = 0 ORDER BY c.cid LIMIT 0, 50 in /var/www/www.4d.com/docs/modules/comment/comment.module on line 991.
  • warning: file_get_contents(http://www.telize.com/geoip/54.161.73.123) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in /var/www/www.4d.com/docs/includes/common.inc(1762) : eval()'d code on line 4.

PHP: It can do it!

06.08.2010
by Thibaud Arguillère

Over several posts, I am spending some time on major new features of 4D v12 (released last June). Today, I’ll focus on a new major major-new-feature: The PHP Execute command, which allows the execution of PHP code.

 

Well, having written “PHP Execute allows the execution of PHP code,” I realize that the name clearly stands for the function. 4D should give enigmatic names to the commands, so I can avoid stating the obvious. For example, “The Execute a script of the kind Hyper Text Preprocessor allows executing PHP code”. Now, we feel like we’re really learning something.

 

Before 4D v12, it was possible to execute PHP code since 2004 (and the 4D version of the same year) via a call to LAUNCH EXTERNAL PROCESS (short name: “LEP”). But the comparison stops there because PHP Execute is so much powerful. Here are 10 reasons to prove this statement (In blue, the good things. In red, the less-good things):
 

 

 

PHP Execute

LEP

1

Need to install PHP

No

Yes1

2

Can run a .php script

Yes 

No2

3

Interpreter re-launched for each call

No

Yes

4

Can execute a function inside a script

Yes

No

5

Can pass parameters to the function

Yes

No3

6

Can receive results

Yes

Partially3

7

Can execute a native PHP function (no need for a .php file)

Yes

Yes4

8

Can send environment variables to the PHP interpreter

Yes

No5

9

Is much more powerful than LEP

Yes

No

10

Is a major new feature of 4D v12

Yes

No

 

(1) Depending on the required version, yes, under Mac OS
(2) Unless PHP is installed
(3) Or difficult. Exchange BLOBs, extract info, etc.
(4) But not that easily. That’s why it’s red.
(5) Eventually, using
stdin

 

It rocks!

And the winner is… PHP Execute, with all the blue points! Okay. You may have noticed that some points have clearly been exaggerated, and others are there only to paint more blue in the appropriate column. The second and fifth points, for example, make sense only if the previous point is valid. That said, the fact is that PHP Execute rocks!

  • Interpreter compiled in FastCGI mode (more on this later) provided => no need to install PHP.
  • No need for the Web server to be running. I’m adding this important detail because most often, PHP is conceptually mixed with “the Web”. This is not the case here: The command works perfectly when 4D Web server is not started. And of course, it also works the same way if the server is running.
  • You can call a function inside a .php script, pass parameters to it, and receive a result. This really, really rocks! To my knowledge, no other tool in the whole universe provides such an easy way to use PHP: One executes full scripts, and then extracts the result sent in stdout.

    In fact, it is not exactly “To my knowledge”. It is more to the knowledge of my colleague Alexandre, who knows all about PHP and worked to develop the feature.

  • Customization: Preferences and calls to SET DATABASE PARAMETER/PHP SET OPTION let the 4D developer change the behavior at runtime.

 

The PHP world is colossal, possibilities are infinite. Prior to 4D v12, when I need a feature that…

 

  • Either just did not exist in 4D
  • or would have required a lot of development time (lot sof code, methods, even some hacks)

 

…I looked for a plug-in that could do it.

 

Whereas now, before looking for a plug-in, I will look on the PHP side. It is very likely that I will find some PHP code, modules, or examples that fit my needs. For example:

  • Your customer needs to communicate with LDAP? PHP can do it! See the “LDAP and v12” US TechNote, and the PHP LDAP module documentation.
  • You need to zip a file or check the content of a zip archive? PHP can do it!
  • You want to get a hash? Use SSL with SMTP? Handle images on disk? Create incredible charts? Encrypt credit card data? Generate PDFs? PHP can do it!

 

If you don’t know PHP, you still can use it. Get the code (text files, .php extension), put it in the right place (I use a “php” folder inside the “resources” folder) and that’s all. You just need to call the script you need, and/or the function inside the script.

 

Well, in fact, you’ll sometimes need to look inside the code. Eventually, you’ll want to write the killer function you need. But the vast quantity of code and examples available on the internet are, most of the time, ok. Back to the “Need to zip a file” example I gave above. When you look at the zip documentation, you can’t miss the “Examples” chapter. The first example explains how to create a new archive and to add elements to it. We quickly can see what looks important for our own use: Here, four routines look very interesting:

PHP example

Using this example (copy-paste), I wrote this script (quick, fast, no error checking, etc.):

 

<?php
function DoZipFile($fileToZipPath, $archivePath)
{
     $zip = new ZipArchive();

     if ($zip->open($archivePath, ZIPARCHIVE::CREATE))
      {
          $zip->addFile($fileToZipPath);
          $zip->close();
      }
}

I save the file as “Zip_Tools.php” (plural form: I’m going to add routines to if, for sure) and put it in {MyDB}/Resources/php.

 

Zipping a file from 4D is now that easy:

 

// Quick test, hard-coded names
$scriptPath:=Get 4D folder(Current Resources folder)+"php"+Folder separator+"Zip_Tools.php"
$filePath:=Convert path system to POSIX(System folder(Desktop)+"TheTestFileToZip.txt")
$zipPath:=$filePath+".zip"
$ok:=PHP Execute($scriptPath;"DoZipFile";*;$filePath;$zipPath)

Please note the use of the Folder separator constant and of Convert path system to POSIX. Cool, hmm?

 

I owe my readers The Truth: The original code (from the example) that was copy/pasted did not work at all on the first try because I removed or moved too many square brackets and parentheses. Thanks to PHP GET FULL RESPONSE, I was able to find my errors.

 

Last word of advice: Don’t forget to create the file to zip on your desktop, if you know what I mean. (Yes, it was the last error of the test.)


“Flash Your Charts with PHP”

Let’s move on to a more sophisticated example. At 4D Summit 2009, the “Flash Your Charts With PHP” session was totally amazing. By mixing PHP code and a Web area, here is an example of the kind of things you can do:
 

 

The demo application can be downloaded here.

 

Tip : A bug in 4D v12.0 makes PHP Execute fail to run if 4D is installed in “Program Files” and you are not the administrator of the machine. This is fixed for 12.1 (and in 12.0HF1 if you are a Partner and have access to the Hot Fixes). As a workaround, you must “Run as administrator.” More details here: http://kb.4d.com/search/assetid=76116

 

FastCGI
The PHP interpreter provided with 4D is compiled using the “FastCGI mode.” This is what allows us to be much, much faster than LEP (though speed is not the one and only advantage of FastCGI). Indeed, in FastCGI mode, the PHP interpreter is loaded in memory only once, upon first execution. The time saved for subsequent executions is huge, because loading a program in memory is a long task. Let’s use an example of calculating the md5 hash of a text. Here is the LEP code:
 

1) The PHP Script:

<%php
echo md5('Hello') ;
?

 

2) The 4D code

C_TEXT($in;$out;$err)
LAUNCH EXTERNAL PROCESS("php -f /Users/thibaud/Desktop/EchoMD5.php";$in;$out;$err)

Note as a tip/trick: You can get the same result without a .php file (point #7 of the comparison array):
 

C_TEXT($in;$out;$err)
LAUNCH EXTERNAL PROCESS("php -r ‘$foo = md5(\"Hello\");var_dump($foo);";$in;$out;$err)
// The result of var_dump is <string(32) "The md5"
// => we must remove the beginning, string(32) + pace + quotes
$out:=Substring($out;13;32)

 

And now, the 4D v12 development style code:

C_TEXT($result)
C_BOOLEAN($ok)
$ok:=PHP Execute("";"md5";$result;"Hello")

See how easy, efficient and elegant it is? Isn’t it nicer to just write "md5" than $result than the ugly
"php -f /Users/thibaud/Desktop/EchoMD5.php"?


If I run this test 100 times, the results are crystal clear on my Mac: It takes 10 seconds for LEP to run the 100 iterations while PHP Execute does the same in 500ms. And if I re-launch the test, then PHP Execute takes only 100ms – one hundred times faster! This is because at first call, 4D launches the interpreter. This takes time, as explained previously so I’m not going to repeat that it’s because of the initializations, loading libraries and system resources, etc. Oh, it sounds like if I repeated it after all. Too bad. Let’s move on. Only the first call has this overhead. Subsequent calls will have a PHP/FastCGI ready to go.

 

On the other hand, each call to LEP loads the shell (we are under Mac OS) which initializes itself. The shell then loads the PHP executable, which initializes itself. Then the script is executed, PHP is unloaded, the shell is unloaded. And – would you look at that – all this is done again at next call.

 

The same test launched on Windows shows that PHP Excecute is “only” 20 times faster than LEP. This is because Windows does not have a Shell – in the UNIX sense – to initialize, and also because loading libraries and system resources are well optimized. But at 20 times faster, it’s still a killer.

 

The End of Plug-ins?

Given the facts that the PHP world is so rich, and how easy it is to find code, examples, and modules on the internet (most of the time free and reusable, but you should always check the licensing scheme, of course), we can figure that the needsfor plug-ins will decrease. Especially since reading PHP code when you don’t know PHP is easier than reading C++ code when you don’t know C++.

 

The subtitle about “The End Of Plug-ins” is provocative on purpose. Plug-ins used for interface (4D Write, Canvas, ALP, hmCal, …) cannot be replaced by PHP (Well, I’ve never tried to at least), but furthermore, PHP is an interpreted scripting language. If speed is critical, use a plug-in. Or 4D compiled code. Back to the previous example, the same 100 iterations takes only 2ms for a plug-in. (Here is the MD5 Plug-in by Pluggers Software, free!) It takes only 12ms for 4D compiled code (interpreted code is out: 2.5s). If you need to calculate an md5 in a trigger, don’t hesitate for a second – use a plug-in!

 

Ok. That’s all for this post. A long one, wasn’t it? I’ll try to be shorter next time but here, I have two main excuses: First of all, PHP Execute is so huge. I only talked about a few points points, but one could fill pages and pages on this topic. Secondly, I’m going on vacation: Naps, board games, swimming pool, rest, eat, Mojito, pool, etc…


See you in a few weeks!

RSS 0 comment(s) to this post