Anyone with BSDI?
If so, please, please, please (with sugar on top) try this patch to PHP 5 today.
Thanks!
If so, please, please, please (with sugar on top) try this patch to PHP 5 today.
Thanks!
Developing PDO and releasing an alpha has sparked a lot of interest already (probably helped along by George ;-)) and we got our first "how does it work" e-mail today. As it happens, I've already written a intro to PDO for the OTN but George informs me that they can take a while to publish.
Meanwhile, to avoid being swamped by mail as the word gets out, here are a couple of sample PDO scripts to get you started. Please keep in mind that it is alpha software (although still works pretty well) and requires PHP 5 from CVS (RC3 will work too, but that isn't released until next week).
The API is "grown-up" by default; you get so called "unbuffered" result sets as standard and the prepare/bind/execute API is preferred, although there are some short-cuts already (and some more planned). Note that you don't need to do any quoting manually using bound parameters; it is handled for you. You do need to be careful with magic_quotes though (as always).
<?php $dbh = new PDO('mysql:dbname=test;host=localhost', $username, $password); // let's have exceptions instead of silence. // other modes: PDO_ERRMODE_SILENT (default - check $stmt->errorCode() and $stmt->errorInfo()) // PDO_ERRMODE_WARNING (php warnings) $dbh->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION); // one-shot query $dbh->exec("create table test(name varchar(255) not null primary key, value varchar(255));"); ?>
<?php // insert some data using a prepared statement $stmt = $dbh->prepare("insert into test (name, value) values (:name, :value)"); // bind php variables to the named placeholders in the query // they are both strings that will not be more than 64 chars long $stmt->bindParam(':name', $name, PDO_PARAM_STR, 64); $stmt->bindParam(':value', $value, PDO_PARAM_STR, 64); // insert a record $name = 'Foo'; $value = 'Bar'; $stmt->execute(); // and another $name = 'Fu'; $value = 'Ba'; $stmt->execute(); // more if you like, but we're done $stmt = null; ?>
<?php // get some data out based on user input $what = $_GET['what']; $stmt = $dbh->prepare('select name, value from test where name=:what'); $stmt->bindParam('what', $what); $stmt->execute(); // get the row using PDO_FETCH_BOTH (default if not specified as parameter) // other modes: PDO_FETCH_NUM, PDO_FETCH_ASSOC, PDO_FETCH_OBJ, PDO_FETCH_LAZY, PDO_FETCH_BOUND $row = $stmt->fetch(); print_r($row); $stmt = null; ?>
<?php // get all data row by row $stmt = $dbh->prepare('select name, value from test'); $stmt->execute(); while ($row = $stmt->fetch(PDO_FETCH_ASSOC)) { print_r($row); } $stmt = null; ?>
<?php // get data row by row using bound ouput columns $stmt = $dbh->prepare('select name, value from test'); $stmt->execute(); $stmt->bindColumn('name', $name); $stmt->bindColumn('value', $value) while ($stmt->fetch(PDO_FETCH_BOUND)) { echo "name=$name, value=$value\\n"; } ?>
Oh, how do you get and install it?
Grab a PHP 5 snapshot from http://snaps.php.net (or HEAD from CVS).
./configure --prefix=/usr/local/php5 --with-zlib .... make make install export PATH="/usr/local/php5/bin:$PATH" /usr/local/php5/bin/pear install -f PDO [ now add extension=pdo.so to php.ini ] /usr/local/php5/bin/pear install -f PDO_MYSQL [ now add extension=pdo_mysql.so to php.ini ] /usr/local/php5/bin/php -m
There are other drivers; Search PECL for more. If you're running windows, just grab the win32 snap and the PDO dlls from PECL binaries for PHP 5.
Credits: thanks to Marcus, George, Ilia and Edin.
Please try to avoid asking too many questions about it; documentation will follow as soon as it is ready.
If you've ever wanted to send more than a basic email through PHP, or perform some processing on existing messages, then you might find my article in the May 2004 issue of php|architect a useful resource.
In the article, I provide you with a functional overview of the major RFCs, some hints on things to watch out for and tips on how best to do things to avoid your mail getting mangled in transit.
[Update: this patch is now in CVS and will be in PHP5RC2]
Today started out good, then it got weird. I felt quite privileged, since a newcomer to the PHP world (employed by Zend) took the time to ask me what the procedure was for publishing an extension in PECL. I felt privileged because the last time a new Zend employee appeared no one said anything to anyone; no introductions; karma was granted and a big new extension just appeared in the repository.
So, today was good. I gave the new-comer a friendly welcoming email. As it turned out, their extension duplicated and/or superceded functionality in the (work-in-progress) cvsclient extension, so I suggested merging it. The newcomer had already contacted the author.
"This is great!" I thought to myself. It then became apparent that the new extension did its stuff by wrapping a CVS binary and parsing the output. While this approach works, it's not really the best thing to put into PECL. Here are two good reasons why:
So we invited the author to join us on IRC and talk about what to do. The conversation, in essence, consisted of Derick and Ilia making their opinions known (they were against the extension, largely due to the reasons I've mentioned above). I'll admit that this can be a bit intimidating (Derick and Ilia aren't known for beating around the bush ;-), but it wasn't a massacre. We learned that:
The conversation lulled, and then I got busy with work.
When I returned and read through the backlog, I could see that things had started to get weird. Zeev had arrived and not happy that we hadn't allowed the extension to be committed yet. The reasons against were made clear, and the reasons for were made clear--it's a working extension that could be used by people right now, and the pty problem meant that it was not possible to implement fully in PEAR. As is typical with discussions between the senior PHP people, it wasn't going anywhere ;-)
Now, I'm quite liberal when it comes to OpenSource. So long as something isn't total garbage it has merits. We hadn't seen the code yet but, being an optimist, I decided that Zend wouldn't hire a total idiot to work on the Zend Engine--so the code probably wasn't garbage. I suggested that we merge the code with the cvsclient extension, and look at implementing the features natively over time, as Sara planned to do with cvsclient anyway. This was surely a definite win:
This was, I thought, warmly received as a good idea by all. Things having returned to normality, I resumed work. When I looked back at the channel a few minutes later, I saw that the discussion had continued and concluded with Zeev leaving in what I can only describe as a huff.
What happened next? A new module was added to CVS for "Public Zend Extensions". WTF? :) Totally bewildered by the crazy turn of events, I posted this message in response to the commit. The module was subsequently renamed to non-pecl and karma granted to the PHP core people.
So, what just happened? I'm not entirely sure. IMO, adding "non-pecl" is crazy. What's the point? PHP extensions are either in the main distro, in PECL, or not distributed by php.net (since we're not behind them). How are we going to manage "non-pecl"? How does it fit into our (PHP) procedures for QA, snapshots, distros and mirrors?
It seems a bit hasty.
Is there a point to all this??
Ah yes. Zeev said something along the lines of "if someone ports it to PEAR, you can delete it from CVS". With that in mind, I've written a patch for proc_open that adds pty support.
Using this patch, you can do something like this in your scripts:
<?php $p = proc_open("cvs -d:pserver:foobar@cvs.php.net:/repository login", array( 0 => array("pty"), 1 => array("pty"), 2 => array("pty"), ), $pipes); ... read stuff from $pipes[1] and $pipes[2] (stdout, stderr) ... ... write stuff to $pipe[0] (stdin) ... ?>
What this does is similar to creating a pipe to the process, but instead creates master (for your script) and slave (for the process you're running) pty handles using the /dev/ptmx interface of your OS. This allows you to send to, and capture data from, applications that open /dev/tty explicitly--and this is generally done when interactively prompting for a password.
What you can't do is any terminal specific ioctl's from PHP land, so you can't make an xterm from PHP ... yet ;)
Another limitation (although not the fault of PHP), is that the pty stuff isn't portable to win32 (where console applications open CON$). As far as I can tell, there is no way to hook or emulate consoles under windows. Likewise, if your flavour of UNIX doesn't support the Unix98 pts interface, you can't use this feature either. The configure script detects the bits required, and everything is protected by #ifdefs in the code, so if you don't have the syscalls required, things should still build and work just as they did before.
Since we're in feature freeze for RC2, I haven't committed this yet. The patch is against HEAD, but should apply cleanly to most PHP 5 snaps or RC's you have around.
Credit where credit is due: the pty support is based on the equivalent part of the code from Shie's new "non-pecl" cvs extension. Thanks Shie for starting the day nicely, and for writing this code! I have a hunch that it was Shie's first day working for Zend and that this was just as weird a turn of events for Shie as for us.
We don't have them, yet, but we might in PHP 5.1. Here's a possible vision that will make both procedural and OO programmers happy. Before the vision, I'll summarize the main problems that need to be solved.
Problems
Solution
For OOP Programmers
Sample for procedural programmers
<?php function do_something_with_a_file($filename) { // ensure that streams functions aren't mapped to exceptions // everything else retains its current exception mapping declare(exception_map='-standard:streams:*') { $fp = @fopen($filename, 'r'); if (!$fp) { if ($_ERROR['code'] == 'standard:streams:E_NOENT') { // handle the case where the file doesn't exist } } } // now the declare block is finished, pop back to original // exception mapping state } ?>
Sample for OO prgrammers
<?php function do_something_with_a_file($filename) { // ensure that streams functions are mapped to exceptions // everything else retains its current exception mapping declare(exception_map='+standard:streams:*') { try { $fp = @fopen($filename, 'r'); } catch (Exception $e) { if ($e->getCode() == 'standard:streams:E_NOENT') { // handle the case where the file doesn't exist } } } // now the declare block is finished, pop back to original // exception mapping state } ?>
As I hope you can see, this allows some flexibility in your code. You can code OO-style if you like. You can mix code snippets written using conflicting a style into your application, since well written libraries will localize their error handling preferences.
The exception mapping syntax used in the declare block should be quite simple to grasp; a plus or a minus character indicates if the pattern should be added to mapping list, or excluded from it. The rest of the string is a simple glob-style string where an asterisk acts as a wildcard. To make multiple changes, without using multiple nested declare blocks, simply separate each one by commas in the string:
<?php // don't map any errors from ext/standard, except // for streams errors declare(exception_map='-standard:*,+standard:streams:*') { ... } ?>
I'm fairly happy with this idea; the only thing is that the syntax in the declare block is a bit weird; it might make sense to come up with an alternative language level keyword. The important point is that any changes made to the mapping stack are popped when control leaves that section of code. If we had the finally statement, then we could do something like this:
<?php function do_something_with_a_file($filename) { // ensure that streams functions aren't mapped to exceptions // everything else retains its current exception mapping push_exception_map('-standard:streams:*'); try { $fp = @fopen($filename, 'r'); if (!$fp) { if ($_ERROR['code'] == 'standard:streams:E_NOENT') { // handle the case where the file doesn't exist } } } finally { pop_exception_map(); } } ?>
I like this better; it's less stuff to hack into the engine.
In conclusion then, I think this possible solution will please pretty much all the people using PHP, whether they are fans of OO or procedural code--you can write your "Enterprise" level code regardless of your preference, and drop-in well written third-party components without worrying so much about how they handle errors.
I welcome your comments!
I found the time to fix up my ffi extension so that it largely usable; the main features that are missing are support for arrays and closures (aka callbacks), but it should otherwise be good enough for some hacking.
ffi is multiplatform, and should work on a wide variety of unices as well as the known-good platforms: Linux/x86, Win32 and OSX.
If you want to try it on win32, you can download the PECL binary for windows; this is updated each time the PHP 5 snapshot is rebuilt--every 3 hours or so.
If you want to try it on other platforms, use pear install ffi
to install and build the code from source; you need to have previously installed PHP 5 to use ffi.
Well, I'm finally back from my conference run. Despite some shortcomings with hotel 'net connections, nothing went badly.
One thing I'm particularly pleased with is that I got to write some code (feels like a long time since I had the luxury to write pleasure code). I'm about 50% of the way through a libffi extension for PHP 5 (the ffi page is out of date, but still relevant).
FFI is an acronym for Foreign Function Interface and it provides a portable way to make calls from PHP into C code (and vice versa) at run-time, without having to write glue specifically for the function being called at compile-time.
PHP already has a w32api interface (unmaintained and broken) that does the same thing but for windows; my ffi extension replaces it and will also work on other platforms (Linux, Darwin, SunOS, Irix, Alpha, m68k, PowerPC and Arm).
Not only can you map functions from shared libraries (and DLLs), but you can also define structured types and access them using a natural syntax (taking advantage of the new OO internals in ZE2).
Even better is that you will also be able to pass PHP functions directly to mapped C functions that take callbacks as parameters (like the C library function qsort).
This all sounds really cool, but there is a price - allowing a PHP script to do this stuff is extremely dangerous (hence the title of this entry), so you won't find it on shared hosters.
It just occurred to me that I didn't publish a link to these SQLite Power Point Slides from the talk that Marcus and myself gave at LinuxTag this year.
I've been lucky enough to have been paid to do some work on the PHP/PECL soap extension over the last couple of days.
I'd like to think that it is a hell of a lot better now than it was when I started - it did segfault when you tried just about anything, and now you can actually use it. Less memory leaks, more fun.
Or something like that.