Archive for the ‘PHP’ Category

They suckered me into helping redesign the website for my daughter's school (don't worry—if you're looking at it before July 27, 2012 it's not my design), and they wanted to go with a WordPress site so lots of people could edit it easily. It seemed like a good idea, but it took 4 weeks of tweaking to get it to the point that everyone liked it.

One thing I wanted to do was have a single settings page for all the relevant options (secretary's email, reCaptcha info for forms), etc. While there are tutorials out there, nothing really hung together for me until I started playing with it. To make it simple, I created a single function that would implement all the settings. It uses PHP 5.3, with namespaces and closures (both of which make life much easier by not polluting the global namespace).

The key is to put all the plugin's code under a single unique namespace, and use that namespace as the index for all the options.

Calling it is simple:

namespace MyUniqueName;
$title="Title for the Plugins Page (short enough to fit in the settings menu)";
plugin_settings($title, $defaults);

$defaults is an array of 'key' => $array, where the $array is array('default value', 'descriptive text', 'callback function'), where 'callback function' is the callable used to display the input element for that option. It can be a string representing the name of the function (prepended with the namespace!) or an anonymous function itself. It is passed a single argument, array('key' => $key), where $key is the key used in the original array.

Use the options as $options = get_option(__NAMESPACE__); $my_option = $options[$key];.

A simple callback function for a text box is:

function text_callback($args){
	$name = $args['key'];
	$ns = __NAMESPACE__; // note that __NAMESPACE__ is used as the index for the options in the database
	$options = get_option($ns);
	echo "<input name='{$ns}[$name]' value='{$options[$name]}' />";		
};

And to make it simpler, I created a function generator to do exactly this: textbox($size=40) returns a callback function to output a text box of $size characters.

So a sample $defaults would be:

$defaults = array(
  'email' => array('info@example.org', 'Main Email Address', textbox()),
  'principal' => array('Ed Rooney', 'Principal\'s Full name', textbox(80))
);
Continue reading ‘Simplifying the Settings API for WordPress’ »

The PHP routines to fill in PDF forms work great, and now my partner wants to use them too. Changing the forms to make the physician name a fill-in field rather than fixed text is easy, but what to do about the signature? It's not like a check; a pixelated image would be fine (I'm not worried about someone forging a preschool physical exam note). But it's not that easy to insert an image into an existing PDF file. I don't want to parse the entire PDF and rewrite it.

Fortunately, images are stored as individual objects in the PDF file, so if there is an image I can identify, I can easily replace it with one of my own choosing. The placement and size of the image on the page is part of the page description, so the new image will be in exactly the same place as the old.

Continue reading ‘Changing Images in a PDF’ »

I use Bing for the search box on bililite.com, and it's worked well; simple API, no need to create a custom search engine as with Google. Unfortunately, Microsoft is losing almost half a million dollars an hour on Bing, and they want me to make up the difference. Well, not me alone, but they are going to start charging for using their web services. Fortunately, they are (as of now) providing a free tier of up to 5,000 queries a month, which is far more than I need.

So I have to sign up for Azure Marketplace (Azure is Microsoft's cloud service) and Subscribe to the Bing Web Search API and create an application key. Then I need to convert my old requests into the new format. Luckily, Microsoft provides a migration guide (as a Word document!), and that includes sample code in PHP. The biggest difference is the need for HTTP authentication. The code from Microsoft works, as long I leave out the proxy line in the context parameters (I guess they only tested their code on local servers) and file_get_contents works on URLs, which is enabled on my service with Nearly Free Speech. I imagine setting the header similarly with cUrl would also work.

The other big difference is that they no longer return the total number of results if not all of them were returned. Now they return a parameter __next (note two underlines) that contains the URL for getting more results if they are available. Since I'm only showing a limited list, I just need to test for the existence of that parameter to indicate that more results are available.

So the updated code is:

Continue reading ‘New Bing API’ »

I'd like to keep my font files on Amazon S3 and save the cost of storing them on my web server. imagettftext doesn't say whether I can use a URL for the font file, but imagettfbbox unambiguously says:

fontfile The name of the TrueType font file (can be a URL).
Unfortunately, they are lying, for both functions. The font file needs to reside in the local filesystem.

But I pay for storage and I want to have plenty of open-source fonts available for the webservices and that adds up. So I have to pull the fonts from Amazon S3 into a temporary file and pass that to imagettftext/imagettfbbox. But then I need to remember to delete the temporary file as soon as I'm done with it, to minimize the storage cost. The only way to guarantee that (that I know about) is with the old C++ techinque Resource Acquisition Is Initialization—create an object that I know will be destroyed and make deleting the file part of that object's destructor. (We usually don't have to worry about that sort of thing in PHP since the most common resource we use is memory, and the garbage collector takes care of deleting unused memory resources).

I also want to keep track of which fonts have already been downloaded, since I can use the same temporary file.

So the following class uses my CDN class for access to the files, and requires a writeable directory for the cache for the temporary files. $fontdir is the local directory where the class looks for the font files initially, pulling then off the S3 server if not available locally.

Continue reading ‘Using imagettftext with Off-site Font URLs’ »

As I wrote, I'm using Amazon S3 to store files that are too expensive to keep on my web server, with the plan of having frequently-updated files on the server and relatively constant stuff on S3. The address for my S3 server is bililite.s3.amazonaws.com, which is stored in the global variable $_SERVER['CDN'].

So to include a file, I would do:

$filename = '/toinclude.php';
if (file_exists($_SERVER['DOCUMENT_ROOT'].$filename)){
  $filename = $_SERVER['DOCUMENT_ROOT'].$filename;
}else{
  $filename = $_SERVER['CDN'].$filename;
}
include ($filename);

Which I use often enough to want to generalize it into a class.

Continue reading ‘Using S3 files in PHP’ »

I use Ulrich Mierendorff's aws_signed_request to create my Amazon Wishlist Widget. But Amazon just changed the terms of their API (which they do with frightening regularity). Luckily, it's a small change: each request now requires an Associate Tag in addition to the AWS key and encryption with the AWS secret key. But if you want to make money off Amazon, you need an Associate Tag anyway. So in the $params that are passed to aws_signed_request be sure to include a parameter "AssociateTag" => $tag. And now it works again. For now.

I guess the idea is to up the ante in Amazon's battle against state sales taxes—they've cut off the associates in states they're in conflict with, and now those users can't use the search API at all.

I hope they don't declare war on Missouri next.

For the bililite webservices, I kept all the data in what I would call "standard" American medical units, centimeters for height, kilograms for weight, mmHg for blood pressure, mg/dl for bilirubin. But lots of doctors use pounds and inches, and it would be nice to allow those as well. I could have separate data entry forms for different units, but I decided it would be easier and more useful to allow units on the numbers. I could allow fractions as well (which some of my medical assistants still insist on recording; 21 5/8 instead of 21.625. My EMR blows a gasket with that, but my program would do better). And then, I could allow mixed units, like a weight of "6 pounds 5 1/2 ounces".

I didn't find anything exactly right on the web, but symcbean on stackoverflow had a clever idea for evaluating fractions: turn "2 1/2" into "2+1/2" then use eval.

Continue reading ‘Fractions and Units in PHP’ »

After playing with creating PDFs with PHP using fPDF for a while, and trying to get everything to work consistently, I discovered tcpdf, which is a fork of fpdf that includes everything that anyone has ever added to the original. And I mean everything; this thing is huge! I printed out the source to see how it differed from the original, and it ran more than 500 pages. Good thing they're so generous to me at work.

Most of the size is due to the SVG and HTML formatting, which I don't need, but the biggest advantage is that Unicode font subsetting works. Mostly.

tfpdf, the Unicode-enabled version that comes with fpdf, supports Unicode fonts but they don't show up on the iPhone. Apple's PDF viewer is somehow different from Adobe's and reads the fonts differently. tcpdf does a better job (displays in Adobe Reader but generates an error for the HumaneJenson font): the Droid fonts work on the iPhone, though the DejaVu fonts do not. Try those last links on the iPhone; the built-in Helvetica fonts show up but DejaVu does not. Try refreshing the test page multiple times; it randomly selects fonts to display each time. Some fonts generate errors in Adobe Reader but display, some don't display at all and some don't display on the iPhone. It all seems very random, but at least I have a set of open-source true type fonts that I can include.

It also does most of the things I need: PNG graphics with transparency, form fields like text boxes (I played with that one for weeks with tfpdf, but it never worked the way I wanted it to), rotating text. The API is clunky and poorly documented and I definitely like my routines better, but this is done and someone else maintains it. A huge advantage. I can write my own interface routines to be more elegant if I want.

Continue reading ‘Don’t Reinvent the Wheel, PDF Style’ »

Looking at FPDF and at my PDF tutorial, it is clear that there are a few things that PDF's can do that aren't part of the API of FPDF. However, FPDF is easily extensible to include everything I might find useful, so I put together a package of those routines.

See the code.

See the sample output.

See the code that produced the sample output.

Continue reading ‘Paths, Vector Graphics and PHP images in FPDF’ »

Now we need to add text. That's the most useful part of a PDF, and the easiest. Also the hardest. Sometimes life is like that.

See the code.

Continue reading ‘Creating PDFs with PHP, part 5: Text’ »