It’s nice when serendipity is your friend! I was porting my Bitly class from Pike to PHP – I know there’s probably a hundred PHP classes already out there, but mine is better coded – and noted by accident that I had used some Pike syntax in my PHP class but it was working anyway. So what was I doing? In Pike there’s separate data type for associative arrays called mapping. In Pike, in general, when merging two objects you just join them with a + sign. Thus merging two mappings you do like
Other than working my ass off at work I just lately took a real approach on my secretly sleeping project PLib. PLib is my own PHP framework with functions and classes to ease my everyday PHP programming.
To give you an idea of what PLib is all about let me give you an example:
18 lines of PHP
<?php
require_once'/path/to/PLib.php';
//! Lets create thumbnails of all JPEG images in a directory
PLib::Import('Graphics.Image');
//! The Dir class is included in Image so I don't explicitly need to
wbr($img->Path());// The full path to the thumbnail
}
?>
Rather easy I think!
AutoDoc
Another cool feature (if I may say so) is the auto documentation. If you quickly want a list of all available classes and functions just type PLib::Info() and you will get the list. Each class and function is then clickable and will lead you to the documentation for which ever class or function you clicked.
If you want the documentation for a specific class just type PLib::Info() and there you have the documentation.
The third way to use the autodoc is to pass an instance of a class as argument like PLib::Info().
And if you wan’t a full documentation site just type PLib::Info() and you will get the same documentation as available at the PLib site.
The site
Anyway, PLib has its site of it’s own where anyone curious can download the latest version of PLib and find out more about the project.
Even though I have my vacation right now I need to hack some
What I have done is a PHP documentation browser, I simply call it PHPDoc Browser, for GNU/Linux to read the PHP documentation locally on the computer (it’s a little bit like CHM for Windows). This little app isn’t that necessary but I thought it was a great thing for learning new stuff: The application is written in Mono/C# and uses SQLite for storing the search index.
Difference from CHM
Although there’s a CHM equivalent, XCHM, for Unix like systems I decided that my application serves a purpose: What I like about the PHP manual is that you can hit www.php.net/the_function in you browser and you will get the documentation for “the_function”. Of course I implemented the same functionality in PHPDoc Browser. You can also do a wild card search like “array_*” and you will get a list of all “array_*” functions.
I also implemented a free text search but that’s not “a real” FTS at the moment. FTS in SQLite in a little bit harder than in MySQL so while awaiting the next SQLite version the FTS is a bit of a hack. But you can quote the search to narrow it down
What’s learned?
Most of the unnecessary stuff I do I do to learn and the PHPDoc Browser is no exception. I learned how to use SQLite in Mono/C# and I also wrote a self contained installer in Bash, and Bash I havn’t really touch although I’ve been using GNU/Linux for 6-7 years! I found it quite fun writing the installer
Howto
If you would like to try it out:
Download the install script
Un-tar it (`tar zxvf phpdocbrowser-installer.tgz`)
Make sure the script is executable (`chmod +x phpdocbrowser-installer`)
Open a console and run the installer: ./phpdocbrowser-installer
Answer the questions and you’r ready to go.
The script will create a directory, ./phpdocbrowser-installer, in your home directory in wich you will find ./phpdocbrowser-installer, ./phpdocbrowser-installer and a directory, ./phpdocbrowser-installer, with the PHP documentation. A “run script” will also be installed either in ./phpdocbrowser-installer or in your home directory depending on how you answered the questions and if you agreed to create a desktop shortcut one will hopefully appear on your desktop (havn’t tested this on KDE but it should work fine in Gnome).
To run the application hit the desktop shortcut, if one was created, or invoke ./phpdocbrowser-installer from a console.
If you wish to remove the PHPDoc Browser run the following from a console: ./phpdocbrowser-installer.
A few bugs was fixed in this release. I also noted a few new ones but that was mostly in the SyntaxMap class which gererates PHP arrays from the SyntaxMap files.
Changelog for this version
Fixed a bug where the end of strings (quotes) wasn’t found correctly in languages that has no escape character (like XSL, XML and HTML).
Also changed the Syntaxer::AutoDetect() method to return the extension of a file if no alias was found. In this way we can pass a path to the method and use the result directly as argument to `Sytaxer::__construct()`
4 lines of PHP
$file='/some/path/to/file.xsl';
$lang= Syntaxer::AutoDetect($file);
$stx=new Syntaxer($lang);
$stx->Parse(file_get_contents($file));
The Syntaxer can be read about and downloaded over here.
I’ve released a new version of my generic syntax highlighting script Syntaxer. I fixed a potential bug where code generated on an operating system that only use \r to define a newline would be messed up (thank you jOOOL at PHPPortalen. Now I’ve bullet proofed (I hope) the way newlines are handled: I replace all \r\n with \r and then replace all \r with \n which means that we always end up with a single \n as the newline character.
A couple of years ago I wrote a generic syntax highlighting script. What I did was using the syntax files from Edit+ to determine how to parse a given language. All languages have different keywords, function names, delimiters and so on, and to know how to highlight a certain language you need to know these things. The Edit+ .stx files describes all these things.
Since I have gotten a few years more of knowledge, and PHP5 has arrived, I though I should write a new version of it. I could reuse some of the code but alot was rewritten and redesigned totally. The script has two classes:
One class to parse the Edit+ syntax files which gets converted into PHP files so that the syntax files doesn’t have to to be parsed for every request. If the given .stx file has a newer timestamp than the cached PHP file the PHP file will be regenerated. Alot of this code could be reused from the older version
The actual highlighting class. This class was almost entirely rewritten. Here I loop through every character of the code to highlight. When a keyword, delimiter or something else detectable is matched I grab that and searches forward to where the rule ends. In the older version I had a different approach where the code was splitted on newlines so I looped through line by line and for each line I looped throuh each charachter and did a similar match as in the new version.
The new approach has some advantages:
There’s no need to duplicate the code wich means a lot less memory is used.
Fewer flags is needed since when I match a detectable rule I at once search for the end of the rule. This means that fewer .stx statements is needed wich speeds thing up alot.
And foremost the code got much much cleaner!
Anyhow! There are a few minor bugs but the code is pretty usable (I have implemented it here in the blogging system). I added the scripts with documentation and a simple example on the server for anyone to download.
The Syntaxer2 can be found and downloaded over here. Some bug fixes and more examples will be done in the very near future.
How many times don’t you write code like this: $var = isset($_GET['var']) ? $_GET['var'] : 'default';? I read an article in Linux Format (the paper issue) about the up and comming PHP6 (well, it will probably take some time until it gets stable but you can already download it) and some of its new functions and stuff and learned that there will be a function called $var = isset($_GET['var']) ? $_GET['var'] : 'default';. This function will work like this: $var = isset($_GET['var']) ? $_GET['var'] : 'default';. Pretty much nicer than the old way!
So I though: How hard can it be to implement the same kind of functionality in a user defined function. Well, it’s not hard att all, and here’s how simple it is:
The only thing noticable here is that the first argument needs to be passed by reference or PHP will throw a warning (depending on the error/warning level set).
Of cource you can escape this issue all together just by choking PHP errors/warnings – $var = isset($_GET['var']) ? $_GET['var'] : 'default'; – but that’s just pure ugly in my opinion.
Just by modifying the function above slightly we also get a nice way for writing: $var = isset($_GET['var']) ? $_GET['var'] : 'default';
I can’t remember the last time I made a web site that wasn’t hooked up to a database in one way or another! There’s nothing wrong with using the database functions that PHP provide directly but if you work with different types of databases – MySQL, Postgres, Oracle, SQL Server, SQLite and so on – you need to remeber how the functions for these databases work, in what order to pass arguments and what not. And maybe you write an application that teoretically could use an abritrary database and not MySQL that you developed the application for, and then it would be nice to use the same function calls no matter what database is being used.
This is where the database abstraction layer comes in handy. There already exist many of them so, again and as always, why bother writing another one? Well, it’s fun and you always learn new stuff and, for good and bad, third party APIs tend to be packed with features that you never use so it get quite tedious learning the API.
So I wrote my own database abstraction layer that only contain the functionality I mostly use. If I need more functionaly it’s easy to implement. When I wrote the abstraction layer I tried to evolve my OOP (object orientated programming) skills (which isn’t too great) so that in it self was I goal.
The abstraction layer contains of two interfaces and two master classes: A connection interface and class and a result interface and class. To create a driver for a new type of database you inherit the master classes and implement the interfaces. This is how the skelleton looks like:
interfaceIDB
The connection interface
interfaceIDBResult
The query result interface
abstract classDB
The connection master class
abstract classDBResult
The query result master class
So a database driver should have two classes: One that extends the DB class and implements the IDB interface and one class that extends the DBResult class and implements the IDBResult interface.
$res=$db->Query("SELECT * FROM table WHERE cat_id = '%d'",$category);
if($res->NumRows()>0){
while($row=$res->Fetch()){
echo"Title: ".$row->title ."<br/>";
}
}
}
//! Could be DBDriverNotFound, DBConnectionFail, DBNotFound, DBQueryFail
catch(Exception $e){
die("Error: ".$e->getMessage();
}
//! SQLite example
try{
$category=$_GET['category'];
$db= DB::Create('SQLite','mysqlitedb');
$db->Connect();
$res=$db->Query("SELECT * FROM table WHERE cat_id = '%d'",$category);
if($res->NumRows()>0){
while($row=$res->Fetch()){
echo"Title: ".$row->title ."<br/>";
}
}
}
//! Could be DBDriverNotFound, DBConnectionFail, DBNotFound, DBQueryFail
catch(Exception $e){
die("Error: ".$e->getMessage();
}
?>
As you can see here we’re using exactly the same code, except for the instantiation of the database object, wether we’re using MySQL or SQLite, and that’s the meaning of the database abstraction layer.
Sources
I currently have two implementations for MySQL and SQLite. The MySQL implementation is what I’m using for this blog and the SQLite implementation is not very well tested yet.
The classes are pretty well documented and the documentation is bundled in the package below.
Sometimes you need/want to find out what mimetype a particular file has. If you have access to the PEAR“Fileinfo Functions” you can use them, but if you don’t here’s a simple solution that might be helpful.
NOTE! This is not as reliable as the Fileinfo Functions but it works in most cases.
In most GNU/Linux systems (if not all) there’s a file called mime.types (in /etc/) which is mapping of mimetype -> extension. The file looks like this:
6 lines of Plain text
application/x-gnumeric gnumeric
application/x-go-sgf sgf
application/x-graphing-calculator gcf
application/x-gtar gtar tgz taz
application/x-hdf hdf
application/x-httpd-php phtml pht php
Quite obvious you could build an array from this file where the mimetype could be the key and the extension(s) the value as an array:
3 lines of PHP
$_MIMETYPES=array(
"mime/type"=>array("ext1","ext2","ext3")
);
When we’ve got this array populated we can easily look up a mimetype for an extention (and vice versa) by these two functions:
The script to convert the mime.types database into an array an auto generate the two functions above looks like this (note that this PHP script is intended to run as a command line (cli) script, thus the shebang (#!/usr/bin/php), since we don’t need to do this conversion run time but only once):
86 lines of PHP
#!/usr/bin/php
<?php
/**
* mimetyper.php
* Turn the /etc/mime.types database into a PHP array
* @author Pontus Ostlund <spam@poppa.se>
*/
//! Mimetype file
$mime_db='/etc/mime.types';
//! Resulting file for the PHP array
$php_file='mimetypes.php';
fileexists($mimedb) or die("No mimetype database ($mime_db) found\\n");
$lines=@file($mimedb) or die("Couldn't read $mimedb");
$fh=@fopen($phpfile,"w+") or die("Couldn't create $phpfile");
$date=strftime("%A %B %d %Y",time());
//! Write the PHP header to the file.
@fwrite($fh,
"<?php
/
* Find mimetype for file extension
* Generated $date by ".basename(<strong>FILE</strong>)."